using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using HSUI.Config;
using HSUI.Helpers;
using HSUI.Interface;
using System.Collections.Generic;
using System.Numerics;

namespace HSUI.Interface.GeneralElements
{
    public class DutyListScenarioHud : DraggableHudElement, IHudElementWithVisibilityConfig
    {
        private DutyListScenarioConfig Config => (DutyListScenarioConfig)_config;
        public VisibilityConfig VisibilityConfig => Config.VisibilityConfig;

        public DutyListScenarioHud(DutyListScenarioConfig config, string displayName)
            : base(config, displayName) { }

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

        /// <summary>Screen-space bounds for visibility "hide unless hovered" must match the draw position exactly.</summary>
        public override (Vector2 min, Vector2 max) GetScreenBounds(Vector2 origin)
        {
            Vector2 topLeft = Utils.GetAnchoredPosition(origin + ParentPos() + Config.Position, Config.Size, Config.Anchor);
            return (topLeft, topLeft + Config.Size);
        }

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

            var dutyListEntries = DutyListScenarioHelper.GetDutyListEntries();
            var scenarioEntries = DutyListScenarioHelper.GetScenarioGuideEntries();
            var dutyFinderInfo = DutyListScenarioHelper.GetDutyFinderQueueInfo();
            var dutyInfo = DutyListScenarioHelper.GetDutyInfo();

            bool hasDutyList = dutyListEntries.Count > 0;
            bool hasScenario = scenarioEntries.Count > 0;
            // Show queue info when in queue; show duty info when in duty (not in queue). Same section, different content.
            bool hasDutyFinder = Config.ShowDutyFinderSection && dutyFinderInfo != null;
            bool hasDutyInfo = Config.ShowDutyFinderSection && dutyInfo != null;

            if (!hasDutyList && !hasScenario && !hasDutyFinder && !hasDutyInfo)
                return;

            Vector2 basePos = Utils.GetAnchoredPosition(origin + Config.Position, Config.Size, Config.Anchor);
            Vector2 iconSize = new Vector2(Config.IconSize, Config.IconSize);
            float lineHeight = Config.IconSize + 4;
            float padding = 6;
            float contentWidth = Config.Size.X - padding * 2;

            AddDrawAction(Config.StrataLevel, () =>
            {
                DrawHelper.DrawInWindow(ID, basePos, Config.Size, true, (drawList) =>
                {
                    uint bgColor = Config.BackgroundColor.Base;
                    if ((bgColor & 0xFF000000) != 0)
                        drawList.AddRectFilled(basePos, basePos + Config.Size, bgColor, 4);
                    drawList.PushClipRect(basePos, basePos + Config.Size, true);

                    float y = basePos.Y + padding;
                    uint textColor = Config.TextColor.Base;

                    if (Config.FontID != "Default" && FontsManager.Instance != null)
                    {
                        using (FontsManager.Instance.PushFont(Config.FontID))
                        {
                            ImGui.SetWindowFontScale(Config.FontScale);
                            DrawContent(drawList, ref y, basePos.X + padding, contentWidth, lineHeight, iconSize, textColor, hasDutyList, hasScenario, hasDutyFinder, hasDutyInfo, dutyListEntries, scenarioEntries, dutyFinderInfo, dutyInfo);
                            ImGui.SetWindowFontScale(1);
                        }
                    }
                    else
                    {
                        ImGui.PushFont(UiBuilder.DefaultFont);
                        ImGui.SetWindowFontScale(Config.FontScale);
                        DrawContent(drawList, ref y, basePos.X + padding, contentWidth, lineHeight, iconSize, textColor, hasDutyList, hasScenario, hasDutyFinder, hasDutyInfo, dutyListEntries, scenarioEntries, dutyFinderInfo, dutyInfo);
                        ImGui.SetWindowFontScale(1);
                        ImGui.PopFont();
                    }
                    drawList.PopClipRect();
                });
            });
        }

        private static string TruncateText(string text, float maxWidth)
        {
            if (ImGui.CalcTextSize(text).X <= maxWidth)
                return text;
            string suffix = "...";
            while (text.Length > 1 && ImGui.CalcTextSize(text + suffix).X > maxWidth)
                text = text[..^1];
            return text + suffix;
        }

        private void DrawContent(
            ImDrawListPtr drawList,
            ref float y,
            float x,
            float contentWidth,
            float lineHeight,
            Vector2 iconSize,
            uint textColor,
            bool hasDutyList,
            bool hasScenario,
            bool hasDutyFinder,
            bool hasDutyInfo,
            List<DutyListScenarioHelper.DutyListEntry> dutyListEntries,
            List<DutyListScenarioHelper.ScenarioGuideEntry> scenarioEntries,
            DutyListScenarioHelper.DutyFinderQueueInfo? dutyFinderInfo,
            DutyListScenarioHelper.DutyInfo? dutyInfo)
        {
            const uint TankIconId = 62581;
            const uint HealerIconId = 62582;
            const uint DPSIconId = 62583;

            if (hasDutyInfo && dutyInfo != null)
            {
                uint titleColor = Config.DutyFinderTitleColor.Base;
                uint detailColor = Config.DutyFinderDetailColor.Base;

                drawList.AddText(new Vector2(x, y), titleColor, "Duty Information");
                y += lineHeight;

                string dutyText = TruncateText(dutyInfo.DutyName, contentWidth);
                drawList.AddText(new Vector2(x, y), detailColor, dutyText);
                y += lineHeight;

                if (!string.IsNullOrEmpty(dutyInfo.TimerText))
                {
                    drawList.AddText(new Vector2(x, y), detailColor, TruncateText(dutyInfo.TimerText, contentWidth));
                    y += lineHeight;
                }

                foreach (var obj in dutyInfo.Objectives)
                {
                    string line = string.IsNullOrWhiteSpace(obj.Text) ? "???" : obj.Text;
                    if (!string.IsNullOrWhiteSpace(obj.Progress))
                        line += ": " + obj.Progress;
                    drawList.AddText(new Vector2(x, y), detailColor, TruncateText(line, contentWidth));
                    y += lineHeight;
                }

                y += 4;
                if (hasScenario || hasDutyList)
                {
                    float divY = y + 2;
                    drawList.AddRectFilled(new Vector2(x, divY), new Vector2(x + contentWidth, divY + 2f), Config.DividerColor.Base);
                    y += 8;
                }
            }
            else if (hasDutyFinder && dutyFinderInfo != null)
            {
                uint titleColor = Config.DutyFinderTitleColor.Base;
                uint detailColor = Config.DutyFinderDetailColor.Base;

                drawList.AddText(new Vector2(x, y), titleColor, "Duty Finder");
                y += lineHeight;

                string dutyText = TruncateText(dutyFinderInfo.DutyName, contentWidth);
                drawList.AddText(new Vector2(x, y), detailColor, dutyText);
                y += lineHeight;

                string statusText = TruncateText(dutyFinderInfo.StatusText, contentWidth);
                drawList.AddText(new Vector2(x, y), detailColor, statusText);
                y += lineHeight;

                float roleX = x;
                roleX += 4;
                DrawHelper.DrawIcon(TankIconId, new Vector2(roleX, y), new Vector2(iconSize.X * 0.8f, iconSize.Y * 0.8f), false, detailColor, drawList);
                roleX += iconSize.X * 0.8f + 2;
                drawList.AddText(new Vector2(roleX, y), detailColor, $":{dutyFinderInfo.TanksFound}/{dutyFinderInfo.TanksNeeded}");
                roleX += ImGui.CalcTextSize($":{dutyFinderInfo.TanksFound}/{dutyFinderInfo.TanksNeeded}").X + 6;
                DrawHelper.DrawIcon(HealerIconId, new Vector2(roleX, y), new Vector2(iconSize.X * 0.8f, iconSize.Y * 0.8f), false, detailColor, drawList);
                roleX += iconSize.X * 0.8f + 2;
                drawList.AddText(new Vector2(roleX, y), detailColor, $":{dutyFinderInfo.HealersFound}/{dutyFinderInfo.HealersNeeded}");
                roleX += ImGui.CalcTextSize($":{dutyFinderInfo.HealersFound}/{dutyFinderInfo.HealersNeeded}").X + 6;
                DrawHelper.DrawIcon(DPSIconId, new Vector2(roleX, y), new Vector2(iconSize.X * 0.8f, iconSize.Y * 0.8f), false, detailColor, drawList);
                roleX += iconSize.X * 0.8f + 2;
                drawList.AddText(new Vector2(roleX, y), detailColor, $":{dutyFinderInfo.DPSFound}/{dutyFinderInfo.DPSNeeded}");
                y += lineHeight;

                string elapsedStr = $"{(int)dutyFinderInfo.TimeElapsed.TotalMinutes}:{dutyFinderInfo.TimeElapsed.Seconds:D2}";
                string timeLine = "Time Elapsed: " + elapsedStr;
                if (!string.IsNullOrEmpty(dutyFinderInfo.AverageWaitText))
                    timeLine += " / Average Wait Time: " + dutyFinderInfo.AverageWaitText;
                timeLine = TruncateText(timeLine, contentWidth);
                drawList.AddText(new Vector2(x, y), detailColor, timeLine);
                y += lineHeight + 4;

                if (hasScenario || hasDutyList)
                {
                    float divY = y + 2;
                    drawList.AddRectFilled(new Vector2(x, divY), new Vector2(x + contentWidth, divY + 2f), Config.DividerColor.Base);
                    y += 8;
                }
            }

            if (hasScenario)
            {
                foreach (var entry in scenarioEntries)
                {
                    float lineX = x;
                    if (Config.ShowQuestIcons && entry.IconId != 0)
                    {
                        DrawHelper.DrawIcon(entry.IconId, new Vector2(lineX, y), iconSize, false, textColor, drawList);
                        lineX += iconSize.X + 4;
                    }

                    string text = TruncateText($"{entry.Label}: Lv. {entry.Level} {entry.QuestName}", contentWidth - (lineX - x));
                    var textSize = ImGui.CalcTextSize(text);
                    drawList.AddText(new Vector2(lineX, y), textColor, text);

                    // Use full line height for hit area so the second line (Job) doesn't get covered by the first (MSQ)
                    if (ImGui.IsMouseHoveringRect(new Vector2(lineX, y), new Vector2(x + contentWidth, y + lineHeight))
                        && ImGui.IsMouseClicked(ImGuiMouseButton.Left))
                    {
                        DutyListScenarioHelper.OpenMapForQuestIssuer(entry.QuestRowId);
                    }

                    y += lineHeight;
                }
                if (hasDutyList)
                {
                    float divY = y + 2;
                    drawList.AddRectFilled(new Vector2(x, divY), new Vector2(x + contentWidth, divY + 2f), Config.DividerColor.Base);
                    y += 8;
                }
            }

            if (hasDutyList)
            {
                uint objectiveColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.78f, 0.78f, 0.78f, 1f));

                foreach (var entry in dutyListEntries)
                {
                    float lineX = x;
                    if (Config.ShowQuestIcons && entry.IconId != 0)
                    {
                        DrawHelper.DrawIcon(entry.IconId, new Vector2(lineX, y), iconSize, false, textColor, drawList);
                        lineX += iconSize.X + 4;
                    }

                    string nameText = TruncateText(entry.QuestName, contentWidth - (lineX - x));
                    var nameSize = ImGui.CalcTextSize(nameText);
                    drawList.AddText(new Vector2(lineX, y), textColor, nameText);

                    if (entry.QuestId != 0
                        && ImGui.IsMouseHoveringRect(new Vector2(lineX, y), new Vector2(lineX + nameSize.X, y + nameSize.Y))
                        && ImGui.IsMouseClicked(ImGuiMouseButton.Left))
                    {
                        DutyListScenarioHelper.OpenJournalForQuest(entry.QuestId);
                    }

                    y += lineHeight;

                    if (!string.IsNullOrWhiteSpace(entry.ObjectiveText))
                    {
                        float objX = lineX + 8;
                        string objText = TruncateText("• " + entry.ObjectiveText, contentWidth - (objX - x));
                        var objSize = ImGui.CalcTextSize(objText);
                        drawList.AddText(new Vector2(objX, y), objectiveColor, objText);

                        if (entry.QuestId != 0
                            && ImGui.IsMouseHoveringRect(new Vector2(objX, y), new Vector2(objX + objSize.X, y + objSize.Y))
                            && ImGui.IsMouseClicked(ImGuiMouseButton.Left))
                        {
                            DutyListScenarioHelper.OpenMapForQuestObjective(entry.QuestId, entry.Sequence);
                        }

                        y += lineHeight;
                    }
                }
            }
        }
    }
}
