using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Style;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Microsoft.Extensions.Logging;

namespace HellionChat.Ui;

internal class Popout : Window
{
    private readonly ChatLogWindow ChatLogWindow;
    private readonly Tab Tab;
    private readonly int Idx;
    private readonly ILogger<Popout> _logger;

    private long FrameTime;
    private long LastActivityTime = Environment.TickCount64;

    // Optional input bar inside the pop-out. Lazy-allocated when enabled,
    // torn down on toggle-off (buffer discarded intentionally).
    public ChatInputBar? InputBar { get; private set; }
    public bool HasFocusedInputBar => InputBar?.IsFocused ?? false;

    // Exposed so AutoTellTabsService can locate this window during LRU eviction.
    internal Guid TabIdentifier => Tab.Identifier;

    public Popout(ChatLogWindow chatLogWindow, Tab tab, int idx, ILogger<Popout> logger)
        : base($"{tab.Name}##popout")
    {
        ChatLogWindow = chatLogWindow;
        Tab = tab;
        Idx = idx;
        _logger = logger;

        Size = new Vector2(350, 350);
        SizeCondition = ImGuiCond.FirstUseEver;

        IsOpen = true;
        RespectCloseHotkey = false;
        DisableWindowSounds = true;
        // AllowBackgroundBlur is intentionally off: Dalamud blurs the entire
        // tab container, not just this window, which would affect adjacent plugins.
        // Users can enable blur per-window via the Dalamud hamburger menu.
    }

    public override void PreOpenCheck()
    {
        if (!Tab.PopOut)
            IsOpen = false;
    }

    public override bool DrawConditions()
    {
        FrameTime = Environment.TickCount64;
        if (Tab.IndependentHide ? HideStateCheck() : ChatLogWindow.IsHidden)
            return false;

        if (
            !Plugin.Config.HideWhenInactive
            || (!Plugin.Config.InactivityHideActiveDuringBattle && Plugin.InBattle)
            || !Tab.UnhideOnActivity
        )
        {
            LastActivityTime = FrameTime;
            return true;
        }

        var lastActivityTime = Math.Max(Tab.LastActivity, LastActivityTime);
        lastActivityTime = Math.Max(lastActivityTime, ChatLogWindow.LastActivityTime);
        return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
    }

    public override void PreDraw()
    {
        // Theme engine pushes the active theme globally in Plugin.Draw;
        // pop-outs draw consistently without per-window overrides.
        Flags = ImGuiWindowFlags.None;
        if (!Plugin.Config.ShowPopOutTitleBar)
            Flags |= ImGuiWindowFlags.NoTitleBar;

        if (!Tab.CanMove)
            Flags |= ImGuiWindowFlags.NoMove;

        if (!Tab.CanResize)
            Flags |= ImGuiWindowFlags.NoResize;

        // Guard against Idx pointing past the end if PopOutDocked was resized mid-frame.
        if (Idx >= 0 && Idx < ChatLogWindow.PopOutDocked.Count && !ChatLogWindow.PopOutDocked[Idx])
        {
            BgAlpha = Tab.IndependentOpacity ? Tab.Opacity / 100f : Plugin.Config.WindowOpacity;
        }
    }

    public override void Draw()
    {
        using var id = ImRaii.PushId($"popout-{Tab.Identifier}");

        if (!Plugin.Config.ShowPopOutTitleBar)
        {
            ImGui.TextUnformatted(Tab.Name);
            ImGui.Separator();
        }

        var hintBannerHeight = DrawHintBannerIfNeeded();

        // Toggle-OFF resets InputBar so the next toggle-ON starts with a fresh buffer.
        var inputEnabled = Plugin.Config.PopOutInputEnabled;
        if (!inputEnabled && InputBar != null)
            InputBar = null;

        if (inputEnabled)
            InputBar ??= new ChatInputBar(ChatLogWindow.Plugin, ChatLogWindow, () => Tab);

        var inputBarHeight = inputEnabled
            ? ImGui.GetFrameHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y
            : 0f;

        var handler = ChatLogWindow.HandlerLender.Borrow();
        var logHeight = ImGui.GetContentRegionAvail().Y - inputBarHeight - hintBannerHeight;
        ChatLogWindow.DrawMessageLog(Tab, handler, logHeight, false, updateScrollState: false);

        if (inputEnabled && InputBar != null)
        {
            ImGui.Separator();
            InputBar.RenderCompact();
        }

        if (ImGui.IsWindowHovered(ImGuiHoveredFlags.ChildWindows))
            LastActivityTime = FrameTime;
    }

    // Returns the vertical space consumed by the banner (0 when not shown).
    private float DrawHintBannerIfNeeded()
    {
        if (Plugin.Config.SeenPopOutInputHint)
            return 0f;

        var hintText = Resources.HellionStrings.Popout_v060_HintText;
        var ackLabel = Resources.HellionStrings.Popout_v060_HintAck;
        var openLabel = Resources.HellionStrings.Popout_v060_HintOpenSettings;

        var startY = ImGui.GetCursorPosY();

        var bg = new System.Numerics.Vector4(0.16f, 0.20f, 0.28f, 1f);
        ImGui.PushStyleColor(ImGuiCol.ChildBg, bg);
        ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1f);

        var dismiss = false;
        var openSettings = false;
        using (
            var child = ImRaii.Child(
                "##v060-pop-out-hint",
                new System.Numerics.Vector2(0f, 64f),
                true
            )
        )
        {
            if (child)
            {
                ImGui.TextWrapped(hintText);
                if (ImGui.Button(ackLabel))
                    dismiss = true;
                ImGui.SameLine();
                if (ImGui.Button(openLabel))
                {
                    dismiss = true;
                    openSettings = true;
                }
            }
        }

        ImGui.PopStyleVar();
        ImGui.PopStyleColor();
        ImGui.Spacing();

        if (dismiss)
        {
            Plugin.Config.SeenPopOutInputHint = true;
            ChatLogWindow.Plugin.SaveConfig();
            _logger.LogDebug("Pop-Out input hint dismissed");
            if (openSettings)
                ChatLogWindow.Plugin.SettingsWindow.Toggle();
        }

        return ImGui.GetCursorPosY() - startY;
    }

    public override void PostDraw()
    {
        if (Idx >= 0 && Idx < ChatLogWindow.PopOutDocked.Count)
            ChatLogWindow.PopOutDocked[Idx] = ImGui.IsWindowDocked();
    }

    public override void OnClose()
    {
        ChatLogWindow.PopOutWindows.Remove(Tab.Identifier);
        ChatLogWindow.Plugin.WindowSystem.RemoveWindow(this);

        Tab.PopOut = false;
        ChatLogWindow.Plugin.SaveConfig();
    }

    private enum HideState
    {
        None,
        Cutscene,
        CutsceneOverride,
        User,
        Battle,
    }

    private HideState CurrentHideState = HideState.None;

    private bool HideStateCheck()
    {
        if (Tab.HideInBattle && CurrentHideState == HideState.None && Plugin.InBattle)
        {
            CurrentHideState = HideState.Battle;
            _logger.LogTrace($"Popout HideState [{Tab.Name}]: None -> Battle");
        }

        if (CurrentHideState is HideState.Battle && !Plugin.InBattle)
        {
            CurrentHideState = HideState.None;
            _logger.LogTrace($"Popout HideState [{Tab.Name}]: Battle -> None");
        }

        if (
            Tab.HideDuringCutscenes
            && CurrentHideState == HideState.None
            && (Plugin.CutsceneActive || Plugin.GposeActive)
        )
        {
            if (ChatLogWindow.Plugin.Functions.Chat.CheckHideFlags())
            {
                CurrentHideState = HideState.Cutscene;
                _logger.LogTrace($"Popout HideState [{Tab.Name}]: None -> Cutscene");
            }
        }

        if (
            CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride
            && !Plugin.CutsceneActive
            && !Plugin.GposeActive
        )
        {
            _logger.LogTrace(
                $"Popout HideState [{Tab.Name}]: {CurrentHideState} -> None (cutscene/gpose ended)"
            );
            CurrentHideState = HideState.None;
        }

        if (CurrentHideState == HideState.Cutscene && ChatLogWindow.Activate)
        {
            CurrentHideState = HideState.CutsceneOverride;
            _logger.LogTrace(
                $"Popout HideState [{Tab.Name}]: Cutscene -> CutsceneOverride (user activate)"
            );
        }

        if (CurrentHideState == HideState.User && ChatLogWindow.Activate)
        {
            CurrentHideState = HideState.None;
            _logger.LogTrace($"Popout HideState [{Tab.Name}]: User -> None (activate)");
        }

        return CurrentHideState is HideState.Cutscene or HideState.User or HideState.Battle
            || (Tab.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn);
    }
}
