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

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

        public SummonerHud(SummonerConfig config, string? displayName = null) : base(config, displayName)
        {
        }

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

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

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

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

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

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

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

            return (positions, sizes);
        }

        public override void DrawJobHud(Vector2 origin, IPlayerCharacter player)
        {
            Vector2 pos = origin + Config.Position;

            if (Config.AetherflowBar.Enabled)
            {
                DrawAetherBar(pos, player);
            }

            if (Config.TranceBar.Enabled)
            {
                DrawTranceBar(pos, player);
            }

            if (Config.IfritBar.Enabled)
            {
                DrawIfritBar(pos, player);
            }

            if (Config.TitanBar.Enabled)
            {
                DrawTitanBar(pos, player);
            }

            if (Config.GarudaBar.Enabled)
            {
                DrawGarudaBar(pos, player);
            }

            if (Config.StacksBar.Enabled)
            {
                HandleAttunementStacks(pos, player);
            }
        }

        private unsafe void DrawIfritBar(Vector2 origin, IPlayerCharacter player)
        {
            SMNGauge gauge = Plugin.JobGauges.Get<SMNGauge>();
            int stackCount = gauge.IsIfritReady ? 1 : 0;

            if (!Config.IfritBar.HideWhenInactive || stackCount > 1)
            {
                BarHud[] bars = BarUtilities.GetChunkedBars(Config.IfritBar, 1, stackCount, 1, 0, player);
                foreach (BarHud bar in bars)
                {
                    AddDrawActions(bar.GetDrawActions(origin, Config.IfritBar.StrataLevel));
                }
            }
        }

        private void DrawTitanBar(Vector2 origin, IPlayerCharacter player)
        {
            SMNGauge gauge = Plugin.JobGauges.Get<SMNGauge>();
            int stackCount = gauge.IsTitanReady ? 1 : 0;

            if (!Config.TitanBar.HideWhenInactive || stackCount > 1)
            {
                BarHud[] bars = BarUtilities.GetChunkedBars(Config.TitanBar, 1, stackCount, 1, 0, player);
                foreach (BarHud bar in bars)
                {
                    AddDrawActions(bar.GetDrawActions(origin, Config.TitanBar.StrataLevel));
                }
            }
        }

        private void DrawGarudaBar(Vector2 origin, IPlayerCharacter player)
        {
            SMNGauge gauge = Plugin.JobGauges.Get<SMNGauge>();
            int stackCount = gauge.IsGarudaReady ? 1 : 0;

            if (!Config.GarudaBar.HideWhenInactive || stackCount > 1)
            {
                BarHud[] bars = BarUtilities.GetChunkedBars(Config.GarudaBar, 1, stackCount, 1, 0, player);
                foreach (BarHud bar in bars)
                {
                    AddDrawActions(bar.GetDrawActions(origin, Config.GarudaBar.StrataLevel));
                }
            }
        }

        private enum Primal
        {
            None = 0,
            Ifrit = 1,
            Titan = 2,
            Garuda = 3
        }

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

            byte value = *((byte*)(new IntPtr(gauge.Address) + 0xE));
            Primal primal = (Primal)(value & 3);
            int stacks = ((value >> 2) & 7);

            if (primal == Primal.Ifrit && Config.StacksBar.ShowIfritStacks)
            {
                DrawStacksBar(origin, player, stacks, 2, Config.StacksBar.IfritStackColor);
            }
            else if (primal == Primal.Titan && Config.StacksBar.ShowTitanStacks)
            {
                DrawStacksBar(origin, player, stacks, 4, Config.StacksBar.TitanStackColor);
            }
            else if (primal == Primal.Garuda && Config.StacksBar.ShowGarudaStacks)
            {
                DrawStacksBar(origin, player, stacks, 4, Config.StacksBar.GarudaStackColor);
            }
            else if (!Config.StacksBar.HideWhenInactive)
            {
                DrawStacksBar(origin, player, 0, 1, Config.StacksBar.FillColor);
            }
        }

        private void DrawAetherBar(Vector2 origin, IPlayerCharacter player)
        {
            ushort stackCount = Utils.StatusListForBattleChara(player).FirstOrDefault(o => o.StatusId == 304)?.Param ?? 0;

            if (Config.AetherflowBar.HideWhenInactive && stackCount == 0)
            {
                return;
            }

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.AetherflowBar, 2, stackCount, 2, 0, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.AetherflowBar.StrataLevel));
            }
        }

        private unsafe void DrawTranceBar(Vector2 origin, IPlayerCharacter player)
        {
            SMNGauge gauge = Plugin.JobGauges.Get<SMNGauge>();
            PluginConfigColor tranceColor;
            uint spellID = 0;
            float maxDuration = 0f;
            float currentCooldown = 0f;
            float tranceDuration = 0f;
            tranceColor = Config.TranceBar.FillColor;

            // Dawntrail Fixes
            bool isSolarBahamutReady = gauge.AetherFlags.HasFlag(AetherFlags.None + 0x8) ||         // 0x8    Formerly Titan Attuned
                                       gauge.AetherFlags.HasFlag(AetherFlags.None + 0xC);           // 0xC    Formerly Garuda Attuned
            bool isPhoenixReady = gauge.AetherFlags.HasFlag(AetherFlags.None + 0x4);                // 0x4    Formerly Ifrit Attuned
            bool isNormalBahamutReady = !isSolarBahamutReady && !isPhoenixReady;                    // You'd think it would be 0x10, but thats unused now

            byte summonedPrimal = *((byte*)(new IntPtr(gauge.Address) + 0xE));                      // Formally Attunement, now...?
            Primal primal = (Primal)(summonedPrimal & 3);

            if (primal != Primal.None)
            {
                tranceColor = primal == Primal.Ifrit ? Config.TranceBar.IfritColor : primal == Primal.Titan ? Config.TranceBar.TitanColor : primal == Primal.Garuda ? Config.TranceBar.GarudaColor : Config.TranceBar.FillColor;
                tranceDuration = gauge.AttunementTimerRemaining;
                maxDuration = 30f;
            }
            else
            {
                if (isSolarBahamutReady)
                {
                    tranceColor = Config.TranceBar.SolarBahamutColor;
                    tranceDuration = gauge.SummonTimerRemaining;
                    spellID = 36992;
                    maxDuration = 15f;
                }
                else if (isNormalBahamutReady)
                {
                    tranceColor = Config.TranceBar.BahamutColor;
                    tranceDuration = gauge.SummonTimerRemaining;
                    spellID = 7427;
                    maxDuration = 15f;
                }
                else if (isPhoenixReady)
                {
                    tranceColor = Config.TranceBar.PhoenixColor;
                    tranceDuration = gauge.SummonTimerRemaining;
                    spellID = 25831;
                    maxDuration = 15f;
                }
            }

            if (tranceDuration != 0)
            {
                if (gauge.AttunementTimerRemaining > 0 && Config.TranceBar.HidePrimals)
                {
                    return;
                }

                Config.TranceBar.Label.SetValue(tranceDuration / 1000f);

                BarHud bar = BarUtilities.GetProgressBar(Config.TranceBar, tranceDuration / 1000f, maxDuration, 0, player, tranceColor);
                AddDrawActions(bar.GetDrawActions(origin, Config.TranceBar.StrataLevel));
            }
            else
            {
                if (!Config.TranceBar.HideWhenInactive)
                {
                    if (gauge.AttunementTimerRemaining == 0)
                    {
                        maxDuration = SpellHelper.Instance.GetRecastTime(spellID);
                        float tranceCooldown = SpellHelper.Instance.GetSpellCooldown(spellID);
                        currentCooldown = maxDuration - tranceCooldown;

                        Config.TranceBar.Label.SetValue(maxDuration - currentCooldown);
                        if (currentCooldown == maxDuration)
                        {
                            Config.TranceBar.Label.SetText("READY");
                        }

                        BarHud bar = BarUtilities.GetProgressBar(Config.TranceBar, currentCooldown, maxDuration, 0, player, tranceColor);
                        AddDrawActions(bar.GetDrawActions(origin, Config.TranceBar.StrataLevel));
                    }
                }
            }
        }

        private void DrawStacksBar(Vector2 origin, IPlayerCharacter player, int amount, int max, PluginConfigColor stackColor, BarGlowConfig? glowConfig = null)
        {
            SummonerStacksBarConfig config = Config.StacksBar;

            config.FillColor = stackColor;

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.StacksBar, max, amount, max, 0f, player, glowConfig: glowConfig);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.StacksBar.StrataLevel));
            }
        }
    }

    [Section("Job Specific Bars")]
    [SubSection("Caster", 0)]
    [SubSection("Summoner", 1)]
    public class SummonerConfig : JobConfig
    {
        [JsonIgnore] public override uint JobId => JobIDs.SMN;
        public new static SummonerConfig DefaultConfig()
        {
            var config = new SummonerConfig();

            config.TranceBar.Label.FontID = FontsConfig.DefaultMediumFontKey;
            config.UseDefaultPrimaryResourceBar = true;

            return config;
        }

        [NestedConfig("Aetherflow Bar", 40)]
        public ChunkedBarConfig AetherflowBar = new ChunkedBarConfig(
            new(-0, -7),
            new(254, 14),
            new(new Vector4(255f / 255f, 177f / 255f, 255f / 255f, 100f / 100f))
        );

        [NestedConfig("Trance Bar", 45)]
        public SummonerTranceBarConfig TranceBar = new SummonerTranceBarConfig(
            new(0, -23),
            new(254, 14),
            new(new Vector4(128f / 255f, 255f / 255f, 255f / 255f, 100f / 100f))
        );

        [NestedConfig("Ifrit Bar", 50)]
        public ChunkedBarConfig IfritBar = new ChunkedBarConfig(
            new(-85, -39),
            new(84, 14),
            new(new Vector4(200f / 255f, 40f / 255f, 0f / 255f, 100f / 100f))
        );

        [NestedConfig("Titan Bar", 55)]
        public ChunkedBarConfig TitanBar = new ChunkedBarConfig(
            new(0, -39),
            new(84, 14),
            new(new Vector4(210f / 255f, 150f / 255f, 26f / 255f, 100f / 100f))
        );

        [NestedConfig("Garuda Bar", 60)]
        public ChunkedBarConfig GarudaBar = new ChunkedBarConfig(
            new(85, -39),
            new(84, 14),
            new(new Vector4(60f / 255f, 160f / 255f, 100f / 255f, 100f / 100f))
        );

        [NestedConfig("Attunement Stacks Bar", 65)]
        public SummonerStacksBarConfig StacksBar = new SummonerStacksBarConfig(
            new(0, -55),
            new(254, 14),
            new PluginConfigColor(new Vector4(255f / 255f, 255f / 255f, 255f / 255f, 0f / 100f))
        );

    }


    [Exportable(false)]
    public class SummonerTranceBarConfig : ProgressBarConfig
    {
        [ColorEdit4("Bahamut Color")]
        [Order(26)]
        public PluginConfigColor BahamutColor = new(new Vector4(128f / 255f, 255f / 255f, 255f / 255f, 100f / 100f));

        [ColorEdit4("Phoenix Color")]
        [Order(27)]
        public PluginConfigColor PhoenixColor = new(new Vector4(240f / 255f, 100f / 255f, 10f / 255f, 100f / 100f));

        [ColorEdit4("Solar Bahamut Color")]
        [Order(28)]
        public PluginConfigColor SolarBahamutColor = new(new Vector4(235f / 255f, 241f / 255f, 252f / 255f, 100f / 100f));

        [ColorEdit4("Ifrit Color")]
        [Order(29)]
        public PluginConfigColor IfritColor = new(new Vector4(200f / 255f, 40f / 255f, 0f / 255f, 100f / 100f));

        [ColorEdit4("Titan Color")]
        [Order(30)]
        public PluginConfigColor TitanColor = new(new Vector4(210f / 255f, 150f / 255f, 26f / 255f, 100f / 100f));

        [ColorEdit4("Garuda Color")]
        [Order(31)]
        public PluginConfigColor GarudaColor = new(new Vector4(60f / 255f, 160f / 255f, 100f / 255f, 100f / 100f));

        [Checkbox("Hide Primals")]
        [Order(45)]
        public bool HidePrimals = false;

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

    [Exportable(false)]
    public class SummonerStacksBarConfig : ChunkedBarConfig
    {
        [Checkbox("Ifrit Stacks", separator = false, spacing = false)]
        [Order(51)]
        public bool ShowIfritStacks = true;

        [Checkbox("Titan Stacks", separator = false, spacing = false)]
        [Order(53)]
        public bool ShowTitanStacks = true;

        [Checkbox("Garuda Stacks", separator = false, spacing = false)]
        [Order(55)]
        public bool ShowGarudaStacks = true;

        [ColorEdit4("Ifrit Stacks Color")]
        [Order(56)]
        public PluginConfigColor IfritStackColor = new(new Vector4(200f / 255f, 40f / 255f, 0f / 255f, 100f / 100f));

        [ColorEdit4("Titan Stacks Color")]
        [Order(57)]
        public PluginConfigColor TitanStackColor = new(new Vector4(210f / 255f, 150f / 255f, 26f / 255f, 100f / 100f));

        [ColorEdit4("Garuda Stacks Color")]
        [Order(58)]
        public PluginConfigColor GarudaStackColor = new(new Vector4(60f / 255f, 160f / 255f, 100f / 255f, 100f / 100f));

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