using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using HellionChat._Helpers;
using HellionChat.Code;
using HellionChat.Resources;
using HellionChat.Util;

namespace HellionChat.Ui;

// Input bar component for pop-out windows. Render() is a stub — the main
// window input layer stays in ChatLogWindow to avoid a high-risk extract.
// RenderCompact() is the only v0.6.0 deliverable; Render() can be filled
// in a later cycle if needed.
public sealed class ChatInputBar
{
    private readonly Plugin _plugin;
    private readonly ChatLogWindow _host;
    private readonly Func<Tab?> _activeTabAccessor;
    private readonly InputState _state = new();

    // UI-11: the buffer for which a plugin-disclosure warning was already
    // shown. A second Enter on the same buffer sends it anyway; editing the
    // buffer clears the arming so the next send is re-checked.
    private string? _disclosureArmedBuffer;

    public ChatInputBar(Plugin plugin, ChatLogWindow host, Func<Tab?> activeTabAccessor)
    {
        _plugin = plugin;
        _host = host;
        _activeTabAccessor = activeTabAccessor;
    }

    public InputState State => _state;
    public bool IsFocused { get; private set; }

    // Stub — main window input is handled in ChatLogWindow.
    public void Render() { }

    // Compact layout for pop-out windows: channel icon button left, text
    // input right. Auto-translate is intentionally excluded — the upstream
    // popup isn't instanciable per window without a larger refactor, and
    // typical pop-out use cases rarely need it. Can be added later if
    // tester feedback warrants it.
    //
    // Channel switching is global via Plugin.Functions.Chat (FFXIV API).
    // Text buffer and history cursor are independent per pop-out.
    public void RenderCompact()
    {
        var tab = _activeTabAccessor();
        if (tab == null)
            return;

        DrawChannelIconButton(tab);
        ImGui.SameLine();
        DrawCompactInput(tab);
    }

    private void DrawCompactInput(Tab tab)
    {
        var inputWidth = ImGui.GetContentRegionAvail().X;
        if (inputWidth < 60f)
            inputWidth = 60f;

        ImGui.SetNextItemWidth(inputWidth);

        // CallbackHistory wires Up/Down navigation to InputHistoryService.
        // Submit detected via IsItemDeactivated + Enter, not EnterReturnsTrue
        // (matches ChatLogWindow behavior).
        const ImGuiInputTextFlags flags = ImGuiInputTextFlags.CallbackHistory;
        ImGui.InputText(
            $"##chat-compact-input-{tab.Identifier}",
            ref _state.Buffer,
            500,
            flags,
            CompactCallback
        );

        IsFocused = ImGui.IsItemActive();

        if (
            ImGui.IsItemDeactivated()
            && (ImGui.IsKeyDown(ImGuiKey.Enter) || ImGui.IsKeyDown(ImGuiKey.KeypadEnter))
        )
        {
            SubmitCompact(tab);
        }

        // UI-11: disclosure warning, visible only while an armed buffer is held
        // unchanged. Editing the buffer clears the condition automatically.
        if (
            Plugin.Config.NotifyPluginDisclosure
            && _disclosureArmedBuffer is not null
            && _state.Buffer == _disclosureArmedBuffer
        )
        {
            ImGui.TextColored(
                ImGuiColors.DalamudYellow,
                HellionStrings.ChatInput_PluginDisclosure_Warning
            );
        }
    }

    // TEST-MIRROR: ../_Helpers/CompactInputSubmitter.cs
    private void SubmitCompact(Tab tab)
    {
        if (
            Plugin.Config.NotifyPluginDisclosure
            && _state.Buffer != _disclosureArmedBuffer
            && PluginDisclosureScanner.ContainsPrivateUseGlyph(_state.Buffer)
        )
        {
            // First send attempt on this exact buffer: arm and hold. The buffer
            // is kept, the warning renders, the user can press Enter again.
            _disclosureArmedBuffer = _state.Buffer;
            return;
        }

        _disclosureArmedBuffer = null;
        CompactInputSubmitter.TrySubmit(_state, tab, _host.SendChatBoxFromExternal);
    }

    // History navigation callback. Cursor math delegated to
    // CompactInputHistoryNavigator; ImGui buffer splice stays here.
    // TEST-MIRROR: ../_Helpers/CompactInputHistoryNavigator.cs
    private int CompactCallback(scoped ref ImGuiInputTextCallbackData data)
    {
        if (data.EventFlag != ImGuiInputTextFlags.CallbackHistory)
            return 0;

        var direction = data.EventKey switch
        {
            ImGuiKey.UpArrow => CompactInputHistoryNavigator.Direction.Up,
            ImGuiKey.DownArrow => CompactInputHistoryNavigator.Direction.Down,
            _ => (CompactInputHistoryNavigator.Direction?)null,
        };
        if (direction is null)
            return 0;

        var (cursor, replacement) = CompactInputHistoryNavigator.Navigate(
            direction.Value,
            _state.HistoryCursor,
            _state.Buffer,
            () => InputHistoryService.Count,
            InputHistoryService.Push,
            InputHistoryService.GetByCursor
        );

        _state.HistoryCursor = cursor;
        if (replacement is null)
            return 0;

        data.DeleteChars(0, data.BufTextLen);
        data.InsertChars(0, replacement);
        return 0;
    }

    private void DrawChannelIconButton(Tab tab)
    {
        var inputType = tab.CurrentChannel.UseTempChannel
            ? tab.CurrentChannel.TempChannel.ToChatType()
            : tab.CurrentChannel.Channel.ToChatType();

        var rgba = Plugin.Config.ChatColours.TryGetValue(inputType, out var c)
            ? c
            : (inputType.DefaultColor() ?? 0xFFFFFFFFu);
        var v3 = ColourUtil.RgbaToVector3(rgba);
        var bg = new Vector4(v3.X, v3.Y, v3.Z, 1f);

        // Black foreground on bright backgrounds, white on dark.
        var luminance = 0.2126f * v3.X + 0.7152f * v3.Y + 0.0722f * v3.Z;
        var fg = luminance > 0.55f ? new Vector4(0f, 0f, 0f, 1f) : new Vector4(1f, 1f, 1f, 1f);

        const string popupId = "chat-channel-picker-compact";
        const float buttonSize = 22f;

        using (ImRaii.PushColor(ImGuiCol.Button, bg))
        using (ImRaii.PushColor(ImGuiCol.ButtonHovered, bg))
        using (ImRaii.PushColor(ImGuiCol.ButtonActive, bg))
        using (ImRaii.PushColor(ImGuiCol.Text, fg))
        {
            // Single-letter glyph as a quick visual cue until a proper icon font lands.
            var label = ChannelGlyph(inputType);
            if (
                ImGui.Button($"{label}##chan-compact", new Vector2(buttonSize, buttonSize))
                && tab.Channel is null
            )
                ImGui.OpenPopup(popupId);
        }

        if (tab.Channel is not null && ImGui.IsItemHovered())
            ImGui.SetTooltip(Resources.Language.ChatLog_SwitcherDisabled);
        else if (ImGui.IsItemHovered())
            ImGui.SetTooltip(inputType.Name());

        using (var popup = ImRaii.Popup(popupId))
        {
            if (popup)
            {
                var channels = _host.GetValidChannels();
                foreach (var (name, channel) in channels)
                    if (ImGui.Selectable(name))
                        _host.SetChannel(channel);
            }
        }
    }

    private static string ChannelGlyph(ChatType type) =>
        type switch
        {
            ChatType.Say => "S",
            ChatType.Yell => "Y",
            ChatType.Shout => "!",
            ChatType.TellIncoming or ChatType.TellOutgoing => "T",
            ChatType.Party or ChatType.CrossParty => "P",
            ChatType.Alliance => "A",
            ChatType.FreeCompany => "F",
            ChatType.NoviceNetwork => "N",
            ChatType.Linkshell1 => "1",
            ChatType.Linkshell2 => "2",
            ChatType.Linkshell3 => "3",
            ChatType.Linkshell4 => "4",
            ChatType.Linkshell5 => "5",
            ChatType.Linkshell6 => "6",
            ChatType.Linkshell7 => "7",
            ChatType.Linkshell8 => "8",
            ChatType.CrossLinkshell1 => "①",
            ChatType.CrossLinkshell2 => "②",
            ChatType.CrossLinkshell3 => "③",
            ChatType.CrossLinkshell4 => "④",
            ChatType.CrossLinkshell5 => "⑤",
            ChatType.CrossLinkshell6 => "⑥",
            ChatType.CrossLinkshell7 => "⑦",
            ChatType.CrossLinkshell8 => "⑧",
            _ => "?",
        };

    // Forwards a tab-cycle keybind delta to the host (single source of truth).
    public void HandleKeybindForward(int delta) => _host.ChangeTabDelta(delta);
}

// Per-window input state. Each ChatInputBar owns one so pop-outs and the
// main window keep independent buffers and history cursors.
public sealed class InputState
{
    public string Buffer = string.Empty;
    public InputChannel? Channel;
    public int HistoryCursor = -1;
}
