using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Bindings.ImGui;
using HSUI.Config;
using HSUI.Enums;
using HSUI.Helpers;
using HSUI.Interface.GeneralElements;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;

namespace HSUI.Interface.Party
{
    public class AllianceFramesHud : DraggableHudElement, IHudElementWithMouseOver, IHudElementWithPreview, IHudElementWithVisibilityConfig
    {
        private AllianceFramesConfigBase Config => (AllianceFramesConfigBase)_config;
        public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;
        private PartyFramesConfigs Configs;

        private Vector2 _contentMargin = new Vector2(2, 2);
        private static readonly int MaxMemberCount = 8;

        private Vector2 _origin;
        private LayoutInfo _layoutInfo;
        private uint _memberCount = 0;
        private bool _layoutDirty = true;

        private readonly List<PartyFramesBar> bars;
        private LabelHud _titleLabelHud;

        public AllianceFramesHud(AllianceFramesConfigBase config, string displayName) : base(config, displayName)
        {
            Configs = PartyFramesConfigs.GetAllianceConfigs();

            config.ValueChangeEvent += OnLayoutPropertyChanged;
            Configs.HealthBar.ValueChangeEvent += OnLayoutPropertyChanged;
            Configs.HealthBar.ColorsConfig.ValueChangeEvent += OnLayoutPropertyChanged;

            bars = new List<PartyFramesBar>(MaxMemberCount);
            for (int i = 0; i < bars.Capacity; i++)
            {
                var bar = new PartyFramesBar("HSUI_allianceFramesBar_" + Config.SlotIndex + "_" + i, Configs);
                bars.Add(bar);
            }

            _titleLabelHud = new LabelHud(Config.TitleLabelConfig);

            AllianceManager.Instance.MembersChangedEvent += OnMembersChanged;
        }

        protected override void InternalDispose()
        {
            foreach (var bar in bars)
            {
                try { bar.Dispose(); }
                catch (Exception ex) { Plugin.Logger.Error($"Error disposing AllianceFramesBar: {ex.Message}"); }
            }
            bars.Clear();

            _config.ValueChangeEvent -= OnLayoutPropertyChanged;
            Configs.HealthBar.ValueChangeEvent -= OnLayoutPropertyChanged;
            Configs.HealthBar.ColorsConfig.ValueChangeEvent -= OnLayoutPropertyChanged;
            AllianceManager.Instance.MembersChangedEvent -= OnMembersChanged;
        }

        private void OnLayoutPropertyChanged(object sender, OnChangeBaseArgs args)
        {
            if (args.PropertyName == "Size" || args.PropertyName == "FillRowsFirst" ||
                args.PropertyName == "BarsAnchor" || args.PropertyName == "Padding" ||
                args.PropertyName == "Rows" || args.PropertyName == "Columns")
            {
                _layoutDirty = true;
            }
        }

        private void OnMembersChanged(AllianceManager sender)
        {
            _layoutDirty = true;
        }

        private void UpdateBars(Vector2 contentStartPos)
        {
            var members = AllianceManager.Instance.GetMembersForOtherAlliance(Config.SlotIndex);
            uint memberCount = (uint)members.Count;
            uint row = 0, col = 0;

            CalculateBarPosition(contentStartPos, Size, out float x, out float y);

            for (int i = 0; i < bars.Count; i++)
            {
                var bar = bars[i];
                if (i >= memberCount)
                {
                    bar.Visible = false;
                    continue;
                }

                bar.Member = members[i];
                bar.Visible = true;

                bar.Position = new Vector2(
                    x + Configs.HealthBar.Size.X * col + (Configs.HealthBar.Padding.X - 1) * col,
                    y + Configs.HealthBar.Size.Y * row + (Configs.HealthBar.Padding.Y - 1) * row
                );

                if (Config.FillRowsFirst)
                {
                    col++;
                    if (col >= _layoutInfo.TotalColCount) { col = 0; row++; }
                }
                else
                {
                    row++;
                    if (row >= _layoutInfo.TotalRowCount) { row = 0; col++; }
                }
            }
        }

        private void UpdateBarsPosition(Vector2 delta)
        {
            foreach (var bar in bars)
                bar.Position = bar.Position + delta;
        }

        private void CalculateBarPosition(Vector2 position, Vector2 spaceSize, out float x, out float y)
        {
            x = position.X;
            y = position.Y;
            if (Config.BarsAnchor == DrawAnchor.Top || Config.BarsAnchor == DrawAnchor.Center || Config.BarsAnchor == DrawAnchor.Bottom)
                x += (spaceSize.X - _layoutInfo.ContentSize.X) / 2f;
            else if (Config.BarsAnchor == DrawAnchor.TopRight || Config.BarsAnchor == DrawAnchor.Right || Config.BarsAnchor == DrawAnchor.BottomRight)
                x += spaceSize.X - _layoutInfo.ContentSize.X;
            if (Config.BarsAnchor == DrawAnchor.Left || Config.BarsAnchor == DrawAnchor.Center || Config.BarsAnchor == DrawAnchor.Right)
                y += (spaceSize.Y - _layoutInfo.ContentSize.Y) / 2f;
            else if (Config.BarsAnchor == DrawAnchor.BottomLeft || Config.BarsAnchor == DrawAnchor.Bottom || Config.BarsAnchor == DrawAnchor.BottomRight)
                y += spaceSize.Y - _layoutInfo.ContentSize.Y;
        }

        private Vector2 Size => new Vector2(
            Config.Columns * Configs.HealthBar.Size.X + (Config.Columns - 1) * Configs.HealthBar.Padding.X,
            Config.Rows * Configs.HealthBar.Size.Y + (Config.Rows - 1) * Configs.HealthBar.Padding.Y
        );

        private void UpdateLayout(Vector2 origin)
        {
            var members = AllianceManager.Instance.GetMembersForOtherAlliance(Config.SlotIndex);
            uint count = (uint)members.Count;
            Vector2 contentStartPos = origin + Config.Position;

            if (_layoutDirty || _memberCount != count)
            {
                _layoutInfo = LayoutHelper.CalculateLayout(
                    Size, Configs.HealthBar.Size, count, Configs.HealthBar.Padding, Config.FillRowsFirst
                );
                UpdateBars(contentStartPos);
            }
            else if (_origin != contentStartPos)
            {
                UpdateBarsPosition(contentStartPos - _origin);
            }

            _layoutDirty = false;
            _origin = contentStartPos;
            _memberCount = count;
        }

        public void StopPreview()
        {
            Config.Preview = false;
            foreach (var bar in bars)
                bar.StopPreview();
        }

        protected override (List<Vector2>, List<Vector2>) ChildrenPositionsAndSizes()
        {
            return (new List<Vector2>() { Config.Position + Size / 2f }, new List<Vector2>() { Size });
        }

        public void StopMouseover()
        {
            foreach (var bar in bars)
                bar.StopMouseover();
        }

        public override void DrawChildren(Vector2 origin)
        {
            if (!_config.Enabled)
                return;

            bool inRaid = AllianceManager.Instance.IsInAllianceRaid;
            var members = AllianceManager.Instance.GetMembersForOtherAlliance(Config.SlotIndex);

            if (!inRaid && !Config.Preview && !Config.ShowWhenNotInRaid)
                return;

            if (members.Count < 1 && !Config.Preview && !Config.ShowWhenNotInRaid)
                return;

            // Show placeholder when not in raid (for positioning) or when Preview is on
            if ((Config.Preview || Config.ShowWhenNotInRaid) && members.Count < 1)
            {
                _layoutInfo = LayoutHelper.CalculateLayout(Size, Configs.HealthBar.Size, 8, Configs.HealthBar.Padding, Config.FillRowsFirst);
                for (int i = 0; i < 8; i++)
                {
                    bars[i].Member = new FakePartyFramesMember(i);
                    bars[i].Visible = true;
                }
                for (int i = 8; i < bars.Count; i++)
                    bars[i].Visible = false;
                CalculateBarPosition(origin + Config.Position, Size, out float px, out float py);
                uint row = 0, col = 0;
                for (int i = 0; i < 8; i++)
                {
                    bars[i].Position = new Vector2(
                        px + Configs.HealthBar.Size.X * col + (Configs.HealthBar.Padding.X - 1) * col,
                        py + Configs.HealthBar.Size.Y * row + (Configs.HealthBar.Padding.Y - 1) * row
                    );
                    if (Config.FillRowsFirst) { col++; if (col >= _layoutInfo.TotalColCount) { col = 0; row++; } }
                    else { row++; if (row >= _layoutInfo.TotalRowCount) { row = 0; col++; } }
                }
                AddDrawAction(StrataLevel.LOWEST, () =>
                {
                    var drawList = ImGui.GetWindowDrawList();
                    Vector2 bgPos = origin + Config.Position - _contentMargin;
                    Vector2 bgSize = Size + _contentMargin * 2;
                    drawList.AddRectFilled(bgPos, bgPos + bgSize, 0x66000000);
                    drawList.AddRect(bgPos, bgPos + bgSize, 0x66FFFFFF);
                });
                for (int i = 0; i < 8; i++)
                    AddDrawActions(bars[i].GetBarDrawActions(origin));
                foreach (var bar in bars)
                    AddDrawActions(bar.GetElementsDrawActions(origin));
                Config.TitleLabelConfig.SetText(Config.FramesLabel + " (Preview)");
                AddDrawAction(Config.TitleLabelConfig.StrataLevel, () => _titleLabelHud.Draw(origin + Config.Position));
                return;
            }

            if (Config.Preview)
            {
                AddDrawAction(StrataLevel.LOWEST, () =>
                {
                    var drawList = ImGui.GetWindowDrawList();
                    Vector2 bgPos = origin + Config.Position - _contentMargin;
                    Vector2 bgSize = Size + _contentMargin * 2;
                    drawList.AddRectFilled(bgPos, bgPos + bgSize, 0x66000000);
                    drawList.AddRect(bgPos, bgPos + bgSize, 0x66FFFFFF);
                });
            }

            UpdateLayout(origin);

            IGameObject? target = Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target;
            int targetIndex = -1;

            for (int i = 0; i < members.Count; i++)
            {
                var member = bars[i].Member;
                if (member != null && target != null && member.ObjectId == target.GameObjectId)
                {
                    targetIndex = i;
                    continue;
                }
                AddDrawActions(bars[i].GetBarDrawActions(origin));
            }

            if (targetIndex >= 0)
                AddDrawActions(bars[targetIndex].GetBarDrawActions(origin, Configs.HealthBar.ColorsConfig.TargetBordercolor));

            foreach (var bar in bars)
                AddDrawActions(bar.GetElementsDrawActions(origin));

            string titleText = Config.FramesLabel;
            if (inRaid && AllianceManager.Instance.TryGetAllianceIndexForSlot(Config.SlotIndex, out int allianceIdx)
                && AllianceManager.Instance.TryGetAllianceLetter(allianceIdx, out string letter))
            {
                titleText = $"Alliance {letter}";
            }
            Config.TitleLabelConfig.SetText(titleText);
            AddDrawAction(Config.TitleLabelConfig.StrataLevel, () =>
            {
                _titleLabelHud.Draw(origin + Config.Position);
            });
        }
    }
}
