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

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

        private string[] _chunkTexts = new string[] { "I", "II", "III" };

        public MonkHud(MonkConfig 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.ChakraBar.Enabled)
            {
                positions.Add(Config.Position + Config.ChakraBar.Position);
                sizes.Add(Config.ChakraBar.Size);
            }

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

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

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

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

            return (positions, sizes);
        }

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

            if (Config.ChakraBar.Enabled)
            {
                DrawChakraGauge(position, player);
            }

            if (Config.BeastChakraStacksBar.Enabled)
            {
                DrawBeastChakraStacksBar(position, player);
            }

            if (Config.MastersGauge.Enabled)
            {
                DrawMastersGauge(position, player);
            }

            if (Config.StancesBar.Enabled)
            {
                DrawFormsBar(position, player);
            }

            if (Config.PerfectBalanceBar.Enabled)
            {
                DrawPerfectBalanceBar(position, player);
            }
        }

        private void DrawChakraGauge(Vector2 origin, IPlayerCharacter player)
        {
            MNKGauge gauge = Plugin.JobGauges.Get<MNKGauge>();
            if (Config.ChakraBar.HideWhenInactive && gauge.Chakra == 0)
            {
                return;
            }

            PluginConfigColor mainColor = Config.ChakraBar.FillColor;
            PluginConfigColor extraColor = Config.ChakraBar.BrotherhoodExtraCharkaColor;

            List<Tuple<PluginConfigColor, float, LabelConfig?>> chunks = new();
            for (int i = 1; i < 6; i++)
            {
                PluginConfigColor color = (gauge.Chakra < i || gauge.Chakra - 5 < i) ? mainColor : extraColor;
                chunks.Add(new(color, i <= gauge.Chakra ? 1 : 0, null));
            }

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.ChakraBar, chunks.ToArray(), player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.ChakraBar.StrataLevel));
            }
        }

        private unsafe void DrawBeastChakraStacksBar(Vector2 origin, IPlayerCharacter player)
        {
            MonkBeastChakraStacksBar config = Config.BeastChakraStacksBar;
            MNKGauge gauge = Plugin.JobGauges.Get<MNKGauge>();
            int stacks = gauge.OpoOpoFury + gauge.RaptorFury + gauge.CoeurlFury;

            if (config.HideWhenInactive && stacks == 0)
            {
                return;
            }

            PluginConfigColor empty = PluginConfigColor.Empty;
            Tuple<PluginConfigColor, float, LabelConfig?>[] chunks =
            [
                new(gauge.OpoOpoFury > 0 ? config.OpoopoColor : empty, 1, null),
                new(gauge.RaptorFury > 0 ? config.RaptorColor : empty, 1, null),
                new(gauge.CoeurlFury > 0 ? config.CoeurlColor : empty, 1, null),
                new(gauge.CoeurlFury > 1 ? config.CoeurlColor : empty, 1, null),
            ];

            BarHud[] bars = BarUtilities.GetChunkedBars(config, chunks, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, config.StrataLevel));
            }
        }

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

            if (Config.MastersGauge.HideWhenInactive &&
                gauge.Nadi == Nadi.None &&
                gauge.BeastChakra[0] == BeastChakra.None &&
                gauge.BeastChakra[1] == BeastChakra.None &&
                gauge.BeastChakra[2] == BeastChakra.None)
            {
                return;
            }

            int[] order = Config.MastersGauge.ChakraOrder;
            int[] hasChakra =
            [
                gauge.Nadi.HasFlag(Nadi.Lunar) ? 1 : 0,
                gauge.BeastChakra[0] != BeastChakra.None ? 1 : 0,
                gauge.BeastChakra[0] != BeastChakra.None ? 1 : 0,
                gauge.BeastChakra[0] != BeastChakra.None ? 1 : 0,
                gauge.Nadi.HasFlag(Nadi.Solar) ? 1 : 0,
            ];

            PluginConfigColor[] colors = new[]
            {
                Config.MastersGauge.LunarNadiColor,
                GetChakraColor(gauge.BeastChakra[0]),
                GetChakraColor(gauge.BeastChakra[1]),
                GetChakraColor(gauge.BeastChakra[2]),
                Config.MastersGauge.SolarNadiColor
            };

            var chunks = new Tuple<PluginConfigColor, float, LabelConfig?>[5];
            for (int i = 0; i < chunks.Length; i++)
            {
                chunks[i] = new(colors[order[i]], hasChakra[order[i]], i == 2 ? Config.MastersGauge.BlitzTimerLabel : null);
            }

            Config.MastersGauge.BlitzTimerLabel.SetValue(gauge.BlitzTimeRemaining / 1000);

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.MastersGauge, chunks, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.MastersGauge.StrataLevel));
            }
        }

        private void DrawFormsBar(Vector2 origin, IPlayerCharacter player)
        {
            // formless fist
            IStatus? formlessFist = Utils.StatusListForBattleChara(player).FirstOrDefault(o => o.StatusId == 2513);
            if (formlessFist != null)
            {
                float remaining = Math.Abs(formlessFist.RemainingTime);

                BarHud bar = BarUtilities.GetProgressBar(
                    Config.StancesBar,
                    null,
                    new LabelConfig[] { Config.StancesBar.FormlessFistLabel },
                    remaining,
                    30f,
                    0,
                    player,
                    Config.StancesBar.FormlessFistColor
                );

                Config.StancesBar.FormlessFistLabel.SetValue(remaining);

                AddDrawActions(bar.GetDrawActions(origin, Config.StancesBar.StrataLevel));
                return;
            }

            // forms
            IStatus? form = Utils.StatusListForBattleChara(player).FirstOrDefault(o => o.StatusId is 107 or 108 or 109);
            if (Config.StancesBar.HideWhenInactive && form is null)
            {
                return;
            }

            int activeFormIndex = form != null ? (int)form.StatusId - 107 : -1;
            PluginConfigColor[] chunkColors = new PluginConfigColor[]
            {
                Config.StancesBar.OpoOpoColor,
                Config.StancesBar.RaptorColor,
                Config.StancesBar.CoeurlColor
            };

            LabelConfig[] chunkLabels = new LabelConfig[]
            {
                Config.StancesBar.FormLabel.Clone(0),
                Config.StancesBar.FormLabel.Clone(1),
                Config.StancesBar.FormLabel.Clone(2)
            };

            var chunks = new Tuple<PluginConfigColor, float, LabelConfig?>[3];
            for (int i = 0; i < chunks.Length; i++)
            {
                LabelConfig label = chunkLabels[i];
                label.SetText(_chunkTexts[i]);

                chunks[i] = new(chunkColors[i], activeFormIndex == i ? 1 : 0, label);
            }

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.StancesBar, chunks, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.StancesBar.StrataLevel));
            }
        }

        private void DrawPerfectBalanceBar(Vector2 origin, IPlayerCharacter player)
        {
            IStatus? perfectBalance = Utils.StatusListForBattleChara(player).Where(o => o.StatusId is 110 && o.RemainingTime > 0f).FirstOrDefault();
            float duration = perfectBalance?.RemainingTime ?? 0f;
            float stacks = perfectBalance?.Param ?? 0f;

            if (Config.PerfectBalanceBar.HideWhenInactive && duration <= 0)
            {  
                return;
            }

            Tuple<PluginConfigColor, float, LabelConfig?>[] chunks = new Tuple<PluginConfigColor, float, LabelConfig?>[3];
            for (int i = 0; i < chunks.Length; i++)
            {
                chunks[i] = new(
                    Config.PerfectBalanceBar.FillColor,
                    i < stacks ? 1f : 0,
                    i == 1 ? Config.PerfectBalanceBar.PerfectBalanceLabel : null
                );
            }

            Config.PerfectBalanceBar.PerfectBalanceLabel.SetValue(duration);

            BarHud[] bars = BarUtilities.GetChunkedBars(Config.PerfectBalanceBar, chunks, player);
            foreach (BarHud bar in bars)
            {
                AddDrawActions(bar.GetDrawActions(origin, Config.PerfectBalanceBar.StrataLevel));
            }
        }

        private PluginConfigColor GetChakraColor(BeastChakra chakra) => chakra switch
        {
            BeastChakra.OpoOpo => Config.MastersGauge.OpoopoChakraColor,
            BeastChakra.Raptor => Config.MastersGauge.RaptorChakraColor,
            BeastChakra.Coeurl => Config.MastersGauge.CoeurlChakraColor,
            _ => new PluginConfigColor(new(0, 0, 0, 0))
        };
    }

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

        public new static MonkConfig DefaultConfig()
        {
            var config = new MonkConfig();

            config.StancesBar.Enabled = false;
            config.MastersGauge.BlitzTimerLabel.HideIfZero = true;
            config.PerfectBalanceBar.PerfectBalanceLabel.HideIfZero = true;

            return config;
        }

        [NestedConfig("Chakra Bar", 35)]
        public ChakraBar ChakraBar = new ChakraBar(
            new(0, -32),
            new(254, 20),
            new(new Vector4(204f / 255f, 115f / 255f, 0f, 100f / 100f))
        );

        [NestedConfig("Fury Stacks Bar", 40)]
        public MonkBeastChakraStacksBar BeastChakraStacksBar = new MonkBeastChakraStacksBar(
            new(0, -32),
            new(254, 20)
        );

        [NestedConfig("Masterful Blitz Bar", 45)]
        public MastersGauge MastersGauge = new MastersGauge(
            new(0, -54),
            new(254, 20)
        );

        [NestedConfig("Forms Bar", 50)]
        public MonkStancesBarConfig StancesBar = new MonkStancesBarConfig(
            new(0, -98),
            new(254, 20)
        );

        [NestedConfig("Perfect Balance Bar", 55)]
        public PerfectBalanceBar PerfectBalanceBar = new PerfectBalanceBar(
            new(0, -76),
            new(254, 20),
            new(new Vector4(150f / 255f, 255f / 255f, 255f / 255f, 100f / 100f))
        );
    }

    public class ChakraBar: ChunkedBarConfig
    {
        [ColorEdit4("Brotherhood Extra Chakra Color")]
        [Order(26)]
        public PluginConfigColor BrotherhoodExtraCharkaColor = new(new Vector4(204f / 255f, 0, 0, 1));

        public ChakraBar(Vector2 position, Vector2 size, PluginConfigColor fillColor, int padding = 2) : base(position, size, fillColor, padding)
        {
        }
    }

    public class PerfectBalanceBar : ChunkedBarConfig
    {
        [NestedConfig("Perfect Balance Duration Text", 50, spacing = true)]
        public NumericLabelConfig PerfectBalanceLabel;

        public PerfectBalanceBar(Vector2 position, Vector2 size, PluginConfigColor fillColor, int padding = 2) : base(position, size, fillColor, padding)
        {
            PerfectBalanceLabel = new NumericLabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center);
        }
    }

    [DisableParentSettings("FillColor", "FillDirection")]
    public class MonkBeastChakraStacksBar : ChunkedBarConfig
    {
        [ColorEdit4("Opo-opo Color")]
        [Order(19)]
        public PluginConfigColor OpoopoColor = PluginConfigColor.FromHex(0xFFFFB3D3);

        [ColorEdit4("Raptor Color")]
        [Order(20)]
        public PluginConfigColor RaptorColor = PluginConfigColor.FromHex(0xFFBF89E5);

        [ColorEdit4("Coeurl Color")]
        [Order(21)]
        public PluginConfigColor CoeurlColor = PluginConfigColor.FromHex(0xFF9AE7C0);

        public MonkBeastChakraStacksBar(Vector2 position, Vector2 size)
            : base(position, size, PluginConfigColor.Empty)
        {
        }
    }

    [DisableParentSettings("FillColor", "FillDirection")]
    public class MastersGauge : ChunkedBarConfig
    {
        [ColorEdit4("Lunar Nadi Color")]
        [Order(19)]
        public PluginConfigColor LunarNadiColor = PluginConfigColor.FromHex(0xFFDA87FF);

        [ColorEdit4("Solar Nadi Color")]
        [Order(20)]
        public PluginConfigColor SolarNadiColor = PluginConfigColor.FromHex(0xFFFFFFCA);

        [ColorEdit4("Opo-opo Color")]
        [Order(21)]
        public PluginConfigColor OpoopoChakraColor = PluginConfigColor.FromHex(0xFFC1527E);

        [ColorEdit4("Raptor Color")]
        [Order(22)]
        public PluginConfigColor RaptorChakraColor = PluginConfigColor.FromHex(0xFF8C67BA);

        [ColorEdit4("Coeurl Color")]
        [Order(23)]
        public PluginConfigColor CoeurlChakraColor = PluginConfigColor.FromHex(0xFF326D5A);

        [DragDropHorizontal("Chakra Order", "Lunar Nadi", "Chakra 1", "Chakra 2", "Chakra 3", "Solar Nadi")]
        [Order(24)]
        public int[] ChakraOrder = new int[] { 0, 1, 2, 3, 4 };

        [NestedConfig("Blitz Timer Text", 50, spacing = true)]
        public NumericLabelConfig BlitzTimerLabel;

        public MastersGauge(Vector2 position, Vector2 size)
            : base(position, size, PluginConfigColor.Empty)
        {
            BlitzTimerLabel = new NumericLabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center);
        }
    }

    [DisableParentSettings("FillColor")]
    public class MonkStancesBarConfig : ChunkedBarConfig
    {
        [ColorEdit4("Opo-opo Color")]
        [Order(19)]
        public PluginConfigColor OpoOpoColor = PluginConfigColor.FromHex(0xFFFFB3D3);

        [ColorEdit4("Raptor Color")]
        [Order(20)]
        public PluginConfigColor RaptorColor = PluginConfigColor.FromHex(0xFFBF89E5);

        [ColorEdit4("Coeurl Color")]
        [Order(21)]
        public PluginConfigColor CoeurlColor = PluginConfigColor.FromHex(0xFF9AE7C0);

        [ColorEdit4("Formless Fist Color")]
        [Order(22)]
        public PluginConfigColor FormlessFistColor = PluginConfigColor.FromHex(0xFF514793);

        [NestedConfig("Form Number Text", 500, spacing = true)]
        public LabelConfig FormLabel;

        [NestedConfig("Formless Fist Duration Text", 1000, separator = false, spacing = true)]
        public NumericLabelConfig FormlessFistLabel;

        public MonkStancesBarConfig(Vector2 position, Vector2 size)
            : base(position, size, PluginConfigColor.Empty)
        {
            FormLabel = new LabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center);

            FormlessFistLabel = new NumericLabelConfig(Vector2.Zero, "", DrawAnchor.Center, DrawAnchor.Center);
            FormlessFistLabel.Enabled = false;
        }
    }
}
