using Dalamud.Bindings.ImGui;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.UI;
using HellionChat.Code;
using HellionChat.Resources;
using HellionChat.Util;

namespace HellionChat.Ui.SettingsTabs;

internal sealed class Tabs : ISettingsTab
{
    private Plugin Plugin { get; }
    private Configuration Mutable { get; }

    public string Name => HellionStrings.Settings_Tab_Tabs + "###tabs-tabs";

    private int ToOpen = -2;

    internal Tabs(Plugin plugin, Configuration mutable)
    {
        Plugin = plugin;
        Mutable = mutable;
    }

    public void Draw(bool sectionJustEntered)
    {
        const string addTabPopup = "add-tab-popup";

        ImGuiUtil.HelpText(HellionStrings.Tabs_Presets_Linkshell_Hint);
        ImGui.Spacing();

        if (ImGuiUtil.IconButton(FontAwesomeIcon.Plus, tooltip: Language.Options_Tabs_Add))
            ImGui.OpenPopup(addTabPopup);

        using (var popup = ImRaii.Popup(addTabPopup))
        {
            if (popup)
            {
                if (ImGui.Selectable(Language.Options_Tabs_NewTab))
                    Mutable.Tabs.Add(new Tab());

                ImGui.Separator();

                if (
                    ImGui.Selectable(
                        string.Format(Language.Options_Tabs_Preset, Language.Tabs_Presets_General)
                    )
                )
                    Mutable.Tabs.Add(TabsUtil.VanillaGeneral);

                if (
                    ImGui.Selectable(
                        string.Format(Language.Options_Tabs_Preset, Language.Tabs_Presets_Event)
                    )
                )
                    Mutable.Tabs.Add(TabsUtil.VanillaEvent);

                if (
                    ImGui.Selectable(
                        string.Format(Language.Options_Tabs_Preset, Language.Tabs_Presets_Tell)
                    )
                )
                    Mutable.Tabs.Add(TabsUtil.VanillaTellExclusive);
            }
        }

        var toRemove = -1;
        var doOpens = ToOpen > -2;
        for (var i = 0; i < Mutable.Tabs.Count; i++)
        {
            var tab = Mutable.Tabs[i];

            // Sub-sections (Channels/Display/Notification/Input/Pop-out) are inlined into
            // this loop body rather than extracted to helpers, because each one closes over
            // the per-iteration `i` and `tab` state. Extraction would mean passing both
            // into every helper without meaningful encapsulation gain.

            // ToOpen controls which tab-item TreeNode is open (e.g. after add/move).
            // This is the outer level — not touched by sectionJustEntered.
            if (doOpens)
                ImGui.SetNextItemOpen(i == ToOpen);

            using var treeNode = ImRaii.TreeNode($"{tab.Name}###tab-{i}");
            if (!treeNode.Success)
                continue;

            using var pushedId = ImRaii.PushId($"tab-{i}");

            if (
                ImGuiUtil.IconButton(
                    FontAwesomeIcon.TrashAlt,
                    tooltip: Language.Options_Tabs_Delete
                )
            )
            {
                toRemove = i;
                ToOpen = -1;
            }

            ImGui.SameLine();

            if (
                ImGuiUtil.IconButton(FontAwesomeIcon.ArrowUp, tooltip: Language.Options_Tabs_MoveUp)
                && i > 0
            )
            {
                (Mutable.Tabs[i - 1], Mutable.Tabs[i]) = (Mutable.Tabs[i], Mutable.Tabs[i - 1]);
                ToOpen = i - 1;
            }

            ImGui.SameLine();

            if (
                ImGuiUtil.IconButton(
                    FontAwesomeIcon.ArrowDown,
                    tooltip: Language.Options_Tabs_MoveDown
                )
                && i < Mutable.Tabs.Count - 1
            )
            {
                (Mutable.Tabs[i + 1], Mutable.Tabs[i]) = (Mutable.Tabs[i], Mutable.Tabs[i + 1]);
                ToOpen = i + 1;
            }

            // Name and Icon are always visible — no sub-section collapse for these.
            ImGui.InputText(
                Language.Options_Tabs_Name,
                ref tab.Name,
                512,
                ImGuiInputTextFlags.EnterReturnsTrue
            );

            // Per-tab icon override added in v1.2.0. Falls back to default mapping if unset.
            ImGui.TextUnformatted(HellionStrings.Tabs_Icon_Label);
            ImGui.SameLine();
            ImGuiUtil.HelpMarker(HellionStrings.Tabs_Icon_HelpMarker);

            var iconCurrent = string.IsNullOrEmpty(tab.Icon) ? "" : tab.Icon;
            var iconPreview =
                iconCurrent.Length == 0 ? HellionStrings.Tabs_Icon_DefaultOption : iconCurrent;
            using (var combo = ImRaii.Combo($"##icon-{i}", iconPreview))
            {
                if (combo.Success)
                {
                    // First option clears the icon and lets the default mapping take over.
                    if (
                        ImGui.Selectable(
                            HellionStrings.Tabs_Icon_DefaultOption,
                            iconCurrent.Length == 0
                        )
                    )
                    {
                        tab.Icon = null;
                    }

                    ImGui.Separator();

                    // Options sourced from TabIconGlyphResolver.PickerOptions (single source of truth).
                    foreach (var option in TabIconGlyphResolver.PickerOptions)
                    {
                        var isSelected = string.Equals(
                            iconCurrent,
                            option,
                            StringComparison.OrdinalIgnoreCase
                        );
                        if (ImGui.Selectable(option, isSelected))
                        {
                            tab.Icon = option;
                        }
                    }
                }
            }

            ImGui.Spacing();

            // ── Sub-section: Channels ─────────────────────────────────────────
            // First because it answers "what does this tab collect?" — most important.
            if (sectionJustEntered)
                ImGui.SetNextItemOpen(false);
            using (
                var secChannels = ImRaii.TreeNode(
                    HellionStrings.Settings_Section_Tab_Channels + $"##sec-channels-{i}"
                )
            )
            {
                if (secChannels.Success)
                {
                    using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false);
                    ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, tab.SelectedChannels);
                    ImGuiUtil.ExtraChatSelector(
                        Language.Options_Tabs_ExtraChatChannels,
                        ref tab.ExtraChatAll,
                        tab.ExtraChatChannels
                    );
                }
            }

            ImGui.Spacing();

            // ── Sub-section: Display ──────────────────────────────────────────
            if (sectionJustEntered)
                ImGui.SetNextItemOpen(false);
            using (
                var secDisplay = ImRaii.TreeNode(
                    HellionStrings.Settings_Section_Tab_Display + $"##sec-display-{i}"
                )
            )
            {
                if (secDisplay.Success)
                {
                    using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false);

                    ImGui.Checkbox(Language.Options_Tabs_ShowTimestamps, ref tab.DisplayTimestamp);

                    using (
                        var combo = ImGuiUtil.BeginComboVertical(
                            Language.Options_Tabs_UnreadMode,
                            tab.UnreadMode.Name()
                        )
                    )
                    {
                        if (combo.Success)
                        {
                            foreach (var mode in Enum.GetValues<UnreadMode>())
                            {
                                if (ImGui.Selectable(mode.Name(), tab.UnreadMode == mode))
                                    tab.UnreadMode = mode;

                                if (mode.Tooltip() is { } tooltip && ImGui.IsItemHovered())
                                    ImGuiUtil.Tooltip(tooltip);
                            }
                        }
                    }

                    // Only relevant when the global hide-when-inactive is on.
                    if (Mutable.HideWhenInactive)
                        ImGui.Checkbox(
                            Language.Options_Tabs_InactivityBehaviour,
                            ref tab.UnhideOnActivity
                        );
                }
            }

            ImGui.Spacing();

            // ── Sub-section: Notification ─────────────────────────────────────
            if (sectionJustEntered)
                ImGui.SetNextItemOpen(false);
            using (
                var secNotif = ImRaii.TreeNode(
                    HellionStrings.Settings_Section_Tab_Notification + $"##sec-notif-{i}"
                )
            )
            {
                if (secNotif.Success)
                {
                    using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false);

                    ImGui.Checkbox(
                        HellionStrings.Tabs_NotificationSound_Enable_Name,
                        ref tab.EnableNotificationSound
                    );
                    ImGuiUtil.HelpMarker(HellionStrings.Tabs_NotificationSound_Description);
                    if (tab.EnableNotificationSound)
                    {
                        using var notifIndent = ImRaii.PushIndent(10.0f);
                        // Build a readable preview label for the currently selected sound.
                        var soundPreview =
                            tab.NotificationSoundId <= 16
                                ? $"{HellionStrings.Tabs_NotificationSound_Option} {tab.NotificationSoundId}"
                                : $"{HellionStrings.Tabs_NotificationSound_CustomOption} {tab.NotificationSoundId - 16}";
                        using (var combo = ImRaii.Combo($"##notif-sound-{i}", soundPreview))
                        {
                            if (combo.Success)
                            {
                                for (uint s = 1; s <= 16; s++)
                                {
                                    if (
                                        ImGui.Selectable(
                                            $"{HellionStrings.Tabs_NotificationSound_Option} {s}",
                                            tab.NotificationSoundId == s
                                        )
                                    )
                                        tab.NotificationSoundId = s;
                                }

                                ImGui.Separator();

                                // Bundled custom sounds (ids 17-19).
                                for (uint n = 1; n <= 3; n++)
                                {
                                    var customId = 16 + n;
                                    if (
                                        ImGui.Selectable(
                                            $"{HellionStrings.Tabs_NotificationSound_CustomOption} {n}",
                                            tab.NotificationSoundId == customId
                                        )
                                    )
                                        tab.NotificationSoundId = customId;
                                }
                            }
                        }

                        // Let the user hear the currently selected sound without waiting
                        // for a real message to arrive in this tab.
                        ImGui.SameLine();
                        if (
                            ImGuiUtil.IconButton(
                                FontAwesomeIcon.Play,
                                tooltip: HellionStrings.Tabs_NotificationSound_Preview
                            )
                        )
                        {
                            var previewId = tab.NotificationSoundId;
                            if (previewId <= 16)
                            {
                                Plugin.Framework.RunOnFrameworkThread(() =>
                                {
                                    unsafe
                                    {
                                        UIGlobals.PlaySoundEffect(previewId);
                                    }
                                });
                            }
                            else
                            {
                                Plugin.CustomAudioPlayer.Play(
                                    (int)previewId - 16,
                                    Mutable.CustomSoundVolume
                                );
                            }
                        }
                    }

                    // Volume is stored as a 0-1 float but shown as 0-100%.
                    // Same field as General → Sound; shown here for convenience.
                    // DragFloatVertical derives its widget ID from the label text and exposes no
                    // override. We inline the equivalent (text label + SetNextItemWidth + DragFloat)
                    // to keep an explicit ##tab-volume-{i} ID, which reads more clearly than relying
                    // on the surrounding PushId("tab-{i}") scope to disambiguate identical labels.
                    // Volume is global (Mutable.CustomSoundVolume) and applies to every tab's
                    // notification sound, so it is shown unconditionally — not gated by the
                    // per-tab EnableNotificationSound toggle.
                    ImGui.TextUnformatted(HellionStrings.Settings_General_CustomSoundVolume_Name);
                    ImGui.SetNextItemWidth(-1);
                    var customSoundVolumePercent = Mutable.CustomSoundVolume * 100f;
                    if (
                        ImGui.DragFloat(
                            $"##tab-volume-{i}",
                            ref customSoundVolumePercent,
                            1f,
                            0f,
                            100f,
                            $"{customSoundVolumePercent:N0}%%",
                            ImGuiSliderFlags.AlwaysClamp
                        )
                    )
                    {
                        Mutable.CustomSoundVolume = customSoundVolumePercent / 100f;
                    }
                    // Applies globally — same value as in General → Sound.
                    ImGuiUtil.HelpMarker(
                        HellionStrings.Settings_General_CustomSoundVolume_Description
                            + "\n\n"
                            + HellionStrings.Settings_Section_Tab_Volume_AllTabsHint
                    );
                }
            }

            ImGui.Spacing();

            // ── Sub-section: Input ────────────────────────────────────────────
            if (sectionJustEntered)
                ImGui.SetNextItemOpen(false);
            using (
                var secInput = ImRaii.TreeNode(
                    HellionStrings.Settings_Section_Tab_Input + $"##sec-input-{i}"
                )
            )
            {
                if (secInput.Success)
                {
                    using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false);

                    ImGui.Checkbox(Language.Options_Tabs_NoInput, ref tab.InputDisabled);
                    if (!tab.InputDisabled)
                    {
                        var input =
                            tab.Channel?.ToChatType().Name()
                            ?? Language.Options_Tabs_NoInputChannel;
                        using (
                            var combo = ImGuiUtil.BeginComboVertical(
                                Language.Options_Tabs_InputChannel,
                                input
                            )
                        )
                        {
                            if (combo.Success)
                            {
                                if (
                                    ImGui.Selectable(
                                        Language.Options_Tabs_NoInputChannel,
                                        tab.Channel == null
                                    )
                                )
                                    tab.Channel = null;

                                foreach (var channel in Enum.GetValues<InputChannel>())
                                    if (
                                        ImGui.Selectable(
                                            channel.ToChatType().Name(),
                                            tab.Channel == channel
                                        )
                                    )
                                        tab.Channel = channel;
                            }
                        }

                        var player = Plugin.ObjectTable.LocalPlayer;
                        if (tab.Channel == InputChannel.Tell && player != null)
                        {
                            ImGui.Checkbox(
                                Language.Options_Tabs_SenderMessages,
                                ref tab.AllSenderMessages
                            );
                            ImGuiUtil.HelpText(Language.Options_Help_SenderMessages);

                            var worlds = Sheets
                                .WorldsOnDatacenter(player)
                                .OrderByDescending(world => world.DataCenter.RowId)
                                .ThenBy(world => world.Name.ToString())
                                .ToList();

                            using (ImRaii.ItemWidth(ImGui.GetWindowWidth() / 3f))
                            {
                                ImGui.Text(Language.Options_Header_Target);
                                ImGui.SameLine();

                                var name = tab.TellTarget.Name;
                                if (ImGui.InputText("##targetInput", ref name, 21))
                                    tab.TellTarget.Name = name;

                                ImGui.SameLine();

                                // Guard against an empty worlds list (character switch or sheet not yet populated)
                                // to avoid an out-of-bounds crash on worlds[selectedWorld].
                                if (worlds.Count == 0)
                                {
                                    ImGui.TextDisabled("(no worlds available)");
                                }
                                else
                                {
                                    var selectedWorld = worlds.FindIndex(world =>
                                        world.RowId == tab.TellTarget.World
                                    );
                                    if (selectedWorld == -1)
                                        selectedWorld = 0;

                                    using (
                                        var combo = ImRaii.Combo(
                                            "###player-world",
                                            worlds[selectedWorld].Name.ToString()
                                        )
                                    )
                                    {
                                        if (combo.Success)
                                        {
                                            var lastDc = worlds.First().DataCenter.RowId;
                                            foreach (var (idx, world) in worlds.Index())
                                            {
                                                if (
                                                    ImGui.Selectable(
                                                        world.Name.ToString(),
                                                        selectedWorld == idx
                                                    )
                                                )
                                                {
                                                    selectedWorld = idx;
                                                    tab.TellTarget.World = worlds[
                                                        selectedWorld
                                                    ].RowId;
                                                }

                                                if (lastDc == world.DataCenter.RowId)
                                                    continue;

                                                lastDc = world.DataCenter.RowId;
                                                ImGui.Separator();
                                            }
                                        }
                                    }
                                }
                            }

                            var target =
                                (Plugin.TargetManager.SoftTarget ?? Plugin.TargetManager.Target)
                                as IPlayerCharacter;
                            using (ImRaii.Disabled(target == null))
                            {
                                if (ImGui.Button("Set to target") && target != null)
                                    tab.TellTarget.FromTarget(target);
                            }
                        }
                    }
                }
            }

            ImGui.Spacing();

            // ── Sub-section: Pop-out window ───────────────────────────────────
            if (sectionJustEntered)
                ImGui.SetNextItemOpen(false);
            using (
                var secPopOut = ImRaii.TreeNode(
                    HellionStrings.Settings_Section_Tab_PopOut + $"##sec-popout-{i}"
                )
            )
            {
                if (secPopOut.Success)
                {
                    using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false);

                    ImGui.Checkbox(Language.Options_Tabs_PopOut, ref tab.PopOut);
                    if (tab.PopOut)
                    {
                        using var _ = ImRaii.PushIndent(10.0f);
                        ImGui.Checkbox(
                            Language.Options_Tabs_IndependentOpacity,
                            ref tab.IndependentOpacity
                        );
                        if (tab.IndependentOpacity)
                            ImGuiUtil.DragFloatVertical(
                                Language.Options_Tabs_Opacity,
                                ref tab.Opacity,
                                0.25f,
                                0f,
                                100f,
                                $"{tab.Opacity:N2}%%",
                                ImGuiSliderFlags.AlwaysClamp
                            );

                        ImGui.Checkbox(
                            Language.Options_Tabs_IndependentHide,
                            ref tab.IndependentHide
                        );
                        if (tab.IndependentHide)
                        {
                            using var __ = ImRaii.PushIndent(10.0f);
                            ImGuiUtil.OptionCheckbox(
                                ref tab.HideDuringCutscenes,
                                Language.Options_HideDuringCutscenes_Name
                            );
                            ImGui.Spacing();

                            ImGuiUtil.OptionCheckbox(
                                ref tab.HideWhenNotLoggedIn,
                                Language.Options_HideWhenNotLoggedIn_Name
                            );
                            ImGui.Spacing();

                            ImGuiUtil.OptionCheckbox(
                                ref tab.HideWhenUiHidden,
                                Language.Options_HideWhenUiHidden_Name
                            );
                            ImGui.Spacing();

                            ImGuiUtil.OptionCheckbox(
                                ref tab.HideInLoadingScreens,
                                Language.Options_HideInLoadingScreens_Name
                            );
                            ImGui.Spacing();

                            ImGuiUtil.OptionCheckbox(
                                ref tab.HideInBattle,
                                Language.Options_HideInBattle_Name
                            );
                            ImGui.Spacing();
                        }

                        ImGuiUtil.OptionCheckbox(ref tab.CanMove, Language.Popout_CanMove_Name);
                        ImGui.Spacing();

                        ImGuiUtil.OptionCheckbox(ref tab.CanResize, Language.Popout_CanResize_Name);
                        ImGui.Spacing();
                    }
                }
            }
        }

        if (toRemove > -1)
        {
            Mutable.Tabs.RemoveAt(toRemove);
            Plugin.WantedTab = 0;
        }

        if (doOpens)
            ToOpen = -2;
    }
}
