using System.Numerics;
using HellionChat.Resources;
using HellionChat.Ui.SettingsTabs;
using HellionChat.Util;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using Dalamud.Bindings.ImGui;

namespace HellionChat.Ui;

internal enum SettingsView
{
    Overview,
    Detail,
}

public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window
{
    internal readonly Plugin Plugin;

    private Configuration Mutable { get; }
    private List<ISettingsTab> Tabs { get; }
    private int CurrentTab;
    private SettingsView View = SettingsView.Overview;
    private readonly SettingsOverview Overview;

    internal SettingsWindow(Plugin plugin) : base($"{Language.Settings_Title.Format(Plugin.PluginName)}###chat2-settings")
    {
        Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse;

        SizeCondition = ImGuiCond.FirstUseEver;
        SizeConstraints = new WindowSizeConstraints
        {
            MinimumSize = new Vector2(475, 600),
            MaximumSize = new Vector2(float.MaxValue, float.MaxValue)
        };

        Plugin = plugin;
        Mutable = new Configuration();

        Overview = new SettingsOverview(this);

        Tabs =
        [
            new General(Plugin, Mutable),
            new Appearance(Plugin, Mutable),
            new SettingsTabs.Themes(Plugin, Mutable),
            new SettingsTabs.Window(Plugin, Mutable),
            new Chat(Plugin, Mutable),
            new SettingsTabs.Tabs(Plugin, Mutable),
            new SettingsTabs.Privacy(Plugin, Mutable),
            new Database(Plugin, Mutable),
            new Information(Mutable),
        ];

        RespectCloseHotkey = false;
        DisableWindowSounds = true;

        Initialise();

        Plugin.Commands.Register("/hellion", "Perform various actions with Hellion Chat.").Execute += Command;
        Plugin.Interface.UiBuilder.OpenConfigUi += Toggle;
    }

    public void Dispose()
    {
        Plugin.Interface.UiBuilder.OpenConfigUi -= Toggle;
        Plugin.Commands.Register("/hellion").Execute -= Command;
    }

    private void Command(string command, string args)
    {
        if (string.IsNullOrWhiteSpace(args))
            Toggle();
    }

    private void Initialise()
    {
        Mutable.UpdateFrom(Plugin.Config, false);
    }

    public override void Draw()
    {
        if (ImGui.IsWindowAppearing())
        {
            Initialise();
            View = SettingsView.Overview;
        }

        // ESC im Detail-View kehrt zur Overview zurück. Window-Focus-Check ist
        // Pflicht — sonst triggert ESC auch wenn der User ein anderes Fenster
        // fokussiert hat und ESC fürs Game-Menü drückt (Codebase-Pattern siehe
        // Util/SearchSelector.cs:37).
        if (View == SettingsView.Detail
            && ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows)
            && ImGui.IsKeyPressed(ImGuiKey.Escape))
        {
            View = SettingsView.Overview;
            return;
        }

        if (View == SettingsView.Overview)
            Overview.Draw();
        else
            DrawDetail();

        ImGui.Separator();
        DrawSaveButtons();
    }

    internal void OpenSection(int tabIndex)
    {
        CurrentTab = tabIndex;
        View = SettingsView.Detail;
    }

    internal void OpenOverview()
    {
        View = SettingsView.Overview;
    }

    private void DrawDetail()
    {
        // Breadcrumb-Header — Akzent-Cyan, klickbar, führt zurück zur Overview
        using (ImRaii.PushColor(ImGuiCol.Text, 0xFF00BED2u))
        using (ImRaii.PushColor(ImGuiCol.Button, 0u))
        using (ImRaii.PushColor(ImGuiCol.ButtonHovered, 0x33FFFFFFu))
        using (ImRaii.PushColor(ImGuiCol.ButtonActive, 0x55FFFFFFu))
        {
            if (ImGui.SmallButton("← Settings"))
            {
                View = SettingsView.Overview;
                return;
            }
        }
        ImGui.SameLine();
        ImGui.TextUnformatted("·");
        ImGui.SameLine();
        ImGui.TextUnformatted(Tabs[CurrentTab].Name.Split("###")[0]);

        ImGui.Spacing();
        ImGui.Separator();
        ImGui.Spacing();

        // Section-Content in voller Breite. Die Tab-Liste links ist überholt:
        // der User ist bereits über die Card-Übersicht navigiert, eine zweite
        // Tab-Liste daneben würde nur den Vanilla-Look zurückbringen. Falls
        // der User in eine andere Section will, geht er zurück zur Overview
        // (Breadcrumb / ESC).
        var style = ImGui.GetStyle();
        var height = ImGui.GetContentRegionAvail().Y - style.FramePadding.Y * 2 - style.ItemSpacing.Y - style.ItemInnerSpacing.Y * 2 - ImGui.CalcTextSize("A").Y;

        using var child = ImRaii.Child("##chat2-settings-detail", new Vector2(-1, height));
        if (child.Success)
            Tabs[CurrentTab].Draw(false);
    }

    private void DrawSaveButtons()
    {
        var save = ImGui.Button(Language.Settings_Save);

        ImGui.SameLine();

        if (ImGui.Button(Language.Settings_SaveAndClose))
        {
            save = true;
            IsOpen = false;
        }

        ImGui.SameLine();

        if (ImGui.Button(Language.Settings_Discard))
        {
            IsOpen = false;
        }

        const string buttonLabel = "Anna's Ko-fi";
        const string buttonLabel2 = "Infi's Ko-fi";

        using (ImRaii.PushColor(ImGuiCol.Button, ColourUtil.RgbaToAbgr(0xFF5E5BFF)))
        using (ImRaii.PushColor(ImGuiCol.ButtonHovered, ColourUtil.RgbaToAbgr(0xFF7775FF)))
        using (ImRaii.PushColor(ImGuiCol.ButtonActive, ColourUtil.RgbaToAbgr(0xFF4542FF)))
        using (ImRaii.PushColor(ImGuiCol.Text, 0xFFFFFFFF))
        {
            var buttonWidth = ImGui.CalcTextSize(buttonLabel).X + ImGui.GetStyle().FramePadding.X * 2;
            var buttonWidth2 = ImGui.CalcTextSize(buttonLabel2).X + ImGui.GetStyle().FramePadding.X * 2;
            ImGui.SameLine(ImGui.GetContentRegionAvail().X - buttonWidth - buttonWidth2 - ImGui.GetStyle().ItemSpacing.X);

            if (ImGui.Button(buttonLabel2))
                Dalamud.Utility.Util.OpenLink("https://ko-fi.com/infiii");

            ImGui.SameLine();

            if (ImGui.Button(buttonLabel))
                Dalamud.Utility.Util.OpenLink("https://ko-fi.com/lojewalo");
        }

        if (!save)
            return;

        // calculate all conditions before updating config
        var hideChanged = !Mutable.HideChat && Mutable.HideChat != Plugin.Config.HideChat;
        var languageChanged = Mutable.LanguageOverride != Plugin.Config.LanguageOverride;
        var fontChanged = Mutable.GlobalFontV2 != Plugin.Config.GlobalFontV2
                          || Mutable.JapaneseFontV2 != Plugin.Config.JapaneseFontV2
                          || Mutable.ItalicFontV2 != Plugin.Config.ItalicFontV2
                          || Mutable.ExtraGlyphRanges != Plugin.Config.ExtraGlyphRanges
                          || Mutable.UseHellionFont != Plugin.Config.UseHellionFont;
        var fontSizeChanged = Math.Abs(Mutable.SymbolsFontSizeV2 - Plugin.Config.SymbolsFontSizeV2) > 0.001
                          || Math.Abs(Mutable.FontSizeV2 - Plugin.Config.FontSizeV2) > 0.001;
        var italicStateChanged = Mutable.ItalicEnabled != Plugin.Config.ItalicEnabled;

        Plugin.Config.UpdateFrom(Mutable, true);

        // save after 60 frames have passed, which should hopefully not
        // commit any changes that cause a crash
        Plugin.DeferredSaveFrames = 60;
        Plugin.MessageManager.ClearAllTabs();
        Plugin.MessageManager.FilterAllTabsAsync();

        if (fontChanged || fontSizeChanged || italicStateChanged)
            Plugin.FontManager.BuildFonts();

        if (languageChanged)
            Plugin.LanguageChanged(Plugin.Interface.UiLanguage);

        if (hideChanged)
            GameFunctions.GameFunctions.SetChatInteractable(true);

        if (Plugin.Config.ShowEmotes)
            _ = EmoteCache.LoadData(); // Fire-and-forget intentional, exceptions are caught inside

        Initialise();
    }
}
