using Dalamud.Game.ClientState.JobGauge.Types;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using HSUI.Config;
using HSUI.Config.Attributes;
using HSUI.Helpers;
using HSUI.Interface.Bars;
using HSUI.Interface.GeneralElements;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;

namespace HSUI.Interface.Jobs
{
    public class ViperHud : JobHud
    {
        private new ViperConfig Config => (ViperConfig)_config;

        public ViperHud(ViperConfig config, string? displayName = null) : base(config, displayName) { }

        protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
        {
            List<Vector2> positions = new List<Vector2>();
            List<Vector2> sizes = new List<Vector2>();

            if (Config.RattlingCoilGauge.Enabled)
            {
                positions.Add(Config.Position + Config.RattlingCoilGauge.Position);
                sizes.Add(Config.RattlingCoilGauge.Size);
            }

            if (Config.Vipersight.Enabled)
            {
                positions.Add(Config.Position + Config.Vipersight.Position);
                sizes.Add(Config.Vipersight.Size);
            }

            if (Config.AnguineTribute.Enabled)
            {
                positions.Add(Config.Position + Config.AnguineTribute.Position);
                sizes.Add(Config.AnguineTribute.Size);
            }

            if (Config.SerpentOfferings.Enabled)
            {
                positions.Add(Config.Position + Config.SerpentOfferings.Position);
                sizes.Add(Config.SerpentOfferings.Size);
            }

            return (positions, sizes);
        }

        public override void DrawJobHud(Vector2 origin, IPlayerCharacter player)
        {
            if (Config.RattlingCoilGauge.Enabled)
            {
                DrawRattlingCoilGauge(origin + Config.Position, player);
            }

            if (Config.Vipersight.Enabled)
            {
                DrawVipersightBar(origin + Config.Position, player);
            }

            if (Config.SerpentOfferings.Enabled)
            {
                DrawSerpentOfferingsBar(origin + Config.Position, player);
            }

            if (Config.AnguineTribute.Enabled)
            {
                DrawAnguineTributeGauge(origin + Config.Position, player);
            }
        }

        private unsafe void DrawVipersightBar(Vector2 origin, IPlayerCharacter player)
        {
            ViperCombo lastUsedActionId = (ViperCombo)SpellHelper.Instance.GetLastUsedActionId();
            ViperComboState comboState;
            bool isAoE = false;

            switch (lastUsedActionId)
            {
                case ViperCombo.SteelMaw:
                case ViperCombo.DreadMaw:
                    isAoE = true;
                    comboState = ViperComboState.Started;
                    break;
                case ViperCombo.SteelFangs:
                case ViperCombo.DreadFangs:
                    comboState = ViperComboState.Started;
                    break;
                case ViperCombo.HuntersBite:
                case ViperCombo.SwiftskinsBite:
                    isAoE = true;
                    comboState = ViperComboState.Finisher;
                    break;
                case ViperCombo.HuntersSting:
                case ViperCombo.SwiftskinsSting:
                    comboState = ViperComboState.Finisher;
                    break;
                default:
                    comboState = ViperComboState.None;
                    break;
            }

            if (Config.Vipersight.HideWhenInactive && comboState == ViperComboState.None)
            {
                return;
            }

            uint leftId = SpellHelper.Instance.GetSpellActionId(isAoE ? (uint)ViperCombo.SteelMaw : (uint)ViperCombo.SteelFangs);
            bool isLeftGlowing = SpellHelper.Instance.IsActionHighlighted(leftId);

            uint rightId = SpellHelper.Instance.GetSpellActionId(isAoE ? (uint)ViperCombo.DreadMaw : (uint)ViperCombo.DreadFangs);
            bool isRightGlowing = SpellHelper.Instance.IsActionHighlighted(rightId);

            List<Tuple<PluginConfigColor, float, LabelConfig?>> chunks = new();
            List<bool> glows = new();

            Tuple<PluginConfigColor, float, LabelConfig?> empty = new(PluginConfigColor.Empty, 1, null);
            Tuple<PluginConfigColor, float, LabelConfig?> start = new(Config.Vipersight.ComboStartColor, 1, null);
            Tuple<PluginConfigColor, float, LabelConfig?> endFlank = new(Config.Vipersight.ComboEndFlankColor, 1, null);
            Tuple<PluginConfigColor, float, LabelConfig?> endHind = new(Config.Vipersight.ComboEndHindColor, 1, null);
            Tuple<PluginConfigColor, float, LabelConfig?> endAoE = new(Config.Vipersight.ComboEndAOEColor, 1, null);

            bool isFlankEnder = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3645 or 3646);
            bool isHindEnder = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3647 or 3648);
            bool noEnder = !isFlankEnder && !isHindEnder;

            switch (comboState)
            {
                case ViperComboState.None:
                    {
                        chunks = [empty, empty, empty, empty];
                        glows = [false, isLeftGlowing, isRightGlowing, false];
                        break;
                    }
                case ViperComboState.Started:
                    {
                        chunks = [empty, start, start, empty];
                        glows = [false, isLeftGlowing || isAoE, isRightGlowing || isAoE, false];
                        break;
                    }
                case ViperComboState.Finisher:
                    {
                        bool isFlankChain = lastUsedActionId == ViperCombo.HuntersSting;
                        bool isHindChain = lastUsedActionId == ViperCombo.SwiftskinsSting;

                        Tuple<PluginConfigColor, float, LabelConfig?> end;

                        if (isFlankEnder)
                        {
                            end = isHindChain ? endHind : endFlank;
                        }
                        else if (isHindEnder)
                        {
                            end = isFlankChain ? endFlank : endHind;
                        }
                        else
                        {
                            end = isFlankChain ? endFlank : isHindChain ? endHind : endAoE;
                        }

                        chunks = [end, start, start, end];
                        glows = [isLeftGlowing, isLeftGlowing, isRightGlowing, isRightGlowing];

                        break;
                    }
            }

            if (Config.Vipersight.Invert)
            {
                chunks.Reverse();
                glows.Reverse();
            }

            BarHud[] bars = BarUtilities.GetChunkedBars(
                Config.Vipersight,
                chunks.ToArray(),
                player,
                Config.Vipersight.GlowConfig,
                glows.ToArray()
            );

            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.Vipersight.StrataLevel));
            }
        }

        private unsafe void DrawRattlingCoilGauge(Vector2 origin, IPlayerCharacter player)
        {
            VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();

            if (Config.RattlingCoilGauge.HideWhenInactive && gauge.RattlingCoilStacks <= 0)
            {
                return;
            }

            int maxStacks = player.Level >= 88 ? 3 : 2;
            BarHud[] bars = BarUtilities.GetChunkedBars(Config.RattlingCoilGauge, maxStacks, gauge.RattlingCoilStacks, maxStacks, 0, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.RattlingCoilGauge.StrataLevel));
            }
        }

        private unsafe void DrawAnguineTributeGauge(Vector2 origin, IPlayerCharacter player)
        {
            VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();

            if (Config.AnguineTribute.HideWhenInactive && gauge.AnguineTribute <= 0)
            {
                return;
            }

            int maxStacks = player.Level >= 96 ? 5 : 4;
            BarHud[] bars = BarUtilities.GetChunkedBars(Config.AnguineTribute, maxStacks, gauge.AnguineTribute, maxStacks, 0, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.AnguineTribute.StrataLevel));
            }
        }

        private unsafe void DrawSerpentOfferingsBar(Vector2 origin, IPlayerCharacter player)
        {
            ViperConfig.SerpentOfferingsBarConfig config = Config.SerpentOfferings;
            VPRGauge gauge = Plugin.JobGauges.Get<VPRGauge>();

            float reawakenedDuration = Utils.StatusListForBattleChara(player).FirstOrDefault(o => o.StatusId is 3670 or 4094 && o.RemainingTime > 0f)?.RemainingTime ?? 0f;
            bool reAwakenedReady = Utils.StatusListForBattleChara(player).Any(o => o.StatusId is 3671) || gauge.SerpentOffering >= 50;
            bool isReawakened = reawakenedDuration > 0;
            bool showReawakened = isReawakened && config.EnableAwakenedTimer;
            
            float serpentOffering = showReawakened && isReawakened ? reawakenedDuration : gauge.SerpentOffering;

            if (Config.SerpentOfferings.HideWhenInactive && gauge.SerpentOffering <= 0)
            {
                return;
            }

            Config.SerpentOfferings.Label.SetValue(serpentOffering);

            BarHud[] bars = BarUtilities.GetChunkedProgressBars(
                config,
                showReawakened ? 1 : 2,
                showReawakened ? reawakenedDuration : serpentOffering,
                showReawakened ? 30f : 100f,
                fillColor: reAwakenedReady ? config.AwakenedColor : config.FillColor
            ); ;

            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.SerpentOfferings.StrataLevel));
            }
        }
    }

    public enum ViperCombo
    {
        SteelFangs = 34606,
        DreadFangs = 34607,
        HuntersSting = 34608,
        SwiftskinsSting = 34609,
        SteelMaw = 34614,
        DreadMaw = 34615,
        HuntersBite = 34616,
        SwiftskinsBite = 34617
    }

    public enum ViperComboState
    {
        None,
        Started,
        Finisher
    }

    [Section("Job Specific Bars")]
    [SubSection("Melee", 0)]
    [SubSection("Viper", 1)]
    public class ViperConfig : JobConfig
    {
        [JsonIgnore] public override uint JobId => JobIDs.VPR;

        public new static ViperConfig DefaultConfig()
        {
            var config = new ViperConfig();
            config.SerpentOfferings.UseChunks = false;

            return config;
        }

        [NestedConfig("Vipersight Bar", 30)]
        public VipersightBarConfig Vipersight = new VipersightBarConfig(
            new(0, -10),
            new(254, 10),
            new(new Vector4(237f / 255f, 141f / 255f, 7f / 255f, 100f / 100f))
        );

        [NestedConfig("Rattling Coil Bar", 40)]
        public ChunkedBarConfig RattlingCoilGauge = new ChunkedBarConfig(
            new(0, -34),
            new(254, 10),
            new(new Vector4(204f / 255f, 40f / 255f, 40f / 255f, 1f))
        );

        [NestedConfig("Serpent Offerings Bar", 45)]
        public SerpentOfferingsBarConfig SerpentOfferings = new SerpentOfferingsBarConfig(
            new(0, -46),
            new(254, 10),
            new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f))
        );

        [NestedConfig("Anguine Tribute Bar", 50)]
        public ChunkedBarConfig AnguineTribute = new ChunkedBarConfig(
            new(0, -58),
            new(254, 10),
            new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f))
        );

        [Exportable(false)]
        public class VipersightBarConfig : ChunkedBarConfig
        {
            [NestedConfig("Show Glow", 39, separator = false, spacing = true)]
            public BarGlowConfig GlowConfig = new BarGlowConfig();

            [ColorEdit4("Combo Start", spacing = true)]
            [Order(41)]
            public PluginConfigColor ComboStartColor = new(new Vector4(230f / 255f, 33f / 255f, 33f / 255f, 100f / 100f));

            [ColorEdit4("Flank Ender")]
            [Order(42)]
            public PluginConfigColor ComboEndFlankColor = new(new Vector4(46f / 255f, 228f / 255f, 42f / 255f, 1f));

            [ColorEdit4("Hind Ender")]
            [Order(43)]
            public PluginConfigColor ComboEndHindColor = new(new Vector4(230f / 255f, 33f / 255f, 33f / 255f, 1f));

            [ColorEdit4("Grim/Default Ender")]
            [Order(44)]
            public PluginConfigColor ComboEndAOEColor = new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f));

            [Checkbox("Invert", spacing = true)]
            [Order(45)]
            public bool Invert = false;

            public VipersightBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor)
                : base(position, size, fillColor)
            {
            }
        }

        [Exportable(false)]
        public class SerpentOfferingsBarConfig : ChunkedProgressBarConfig
        {
            [Checkbox("Enable Awakened Timer", spacing = true)]
            [Order(46)]
            public bool EnableAwakenedTimer = true;

            [ColorEdit4("Ready to Reawaken Color")]
            [Order(47)]
            public PluginConfigColor AwakenedColor = new(new Vector4(69f / 255f, 115f / 255f, 202f / 255f, 1f));

            public SerpentOfferingsBarConfig(Vector2 position, Vector2 size, PluginConfigColor fillColor)
                : base(position, size, fillColor)
            {
            }
        }
    }
}