#pragma once
#include <Windows.h>
#include <atomic>
#include <string>

/// Manages the console window lifecycle and guards against QuickEdit blocking.
///
/// QuickEdit selection (click-drag in conhost) blocks WriteConsoleW and stalls
/// ALL threads that try to write to stdout. The guard thread detects this and
/// cancels the selection by posting Esc directly to conhost's message queue.
///
/// Additionally monitors and restores the console title to prevent external
/// interference (e.g. other processes or conhost itself changing it).

class Console
{
public:
    static Console* Get();

    /// One-time setup: title, icon, close-button lock, stderr redirect,
    /// and start of the background guard thread.
    void Initialize();

    /// Signal the guard thread to stop and wait for it to exit.
    /// Safe to call multiple times; call before CRT handles become invalid.
    void Shutdown();

    /// Show or hide the console window.
    void SetVisible(bool visible);

    /// If the console is in QuickEdit selection mode (conhost changed the
    /// title to "选择…" / "Select…"), send Esc immediately to cancel it.
    /// Call this before showing UI that might trigger log output, so the
    /// console doesn't get stuck waiting for selection to end.
    void CancelSelectionIfActive();

    // ---- Called by Log ---------------------------------------------------
    /// Mark that a WriteConsoleW call is about to happen.
    /// If the guard thread sees this flag stay set for >100 ms it knows
    /// QuickEdit is blocking output and cancels the selection.
    static void NotifyOutputPending();
    /// Mark that WriteConsoleW has returned normally.
    static void NotifyOutputDone();

private:
    Console()  = default;
    ~Console();

    Console(const Console&)            = delete;
    Console& operator=(const Console&) = delete;

    // Background thread entry point.
    static DWORD WINAPI GuardThreadProc(LPVOID);

    // Swallow Ctrl+C so the user can't accidentally kill the process
    // from the console. Returns TRUE for CTRL_C_EVENT.
    static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType);

    // Refresh the console HWND (in case conhost recreated the window).
    void RefreshConsoleHandle();

    // Remove the console window from the taskbar so "Close window" is
    // not available.  Also strips SC_CLOSE from the system menu.
    // Called from Initialize() and periodically from the guard thread.
    void HardenWindow(HWND hwnd);

    // Check the console title every tick (100 ms).
    // If conhost changed it to the QuickEdit "Select..." indicator
    // ("选择 Rcjy" / "Select Rcjy"), begin a 500 ms countdown; when the
    // countdown expires, send Esc to cancel selection mode and restore the
    // original title.  Other external title changes are restored immediately.
    void CheckAndRestoreTitle();

    // ---- thread / sync ---------------------------------------------------
    HANDLE m_hThread    = NULL;
    HANDLE m_hWakeEvent = NULL;   // auto-reset; set to interrupt the guard's wait

    // ---- window ----------------------------------------------------------
    HWND         m_hConWnd       = NULL;
    std::wstring m_originalTitle;

    // ---- state -----------------------------------------------------------
    bool              m_bInitialized = false;
    std::atomic<bool> m_bRunning     = false;

    // Title-based selection detection (only touched by guard thread)
    bool m_bSelectionDetected = false;
    int  m_nSelectionDelay    = 0;   // remaining 100ms ticks (>0 = counting)

    // Shared with Log — set before WriteConsoleW, cleared after.
    static std::atomic<bool> s_bOutputPending;
};
