// ==========================================================
// test_window_utils.cpp - Unit Tests for Win32 Window Utilities & Focus Interlock
// AutoPOE2 Core Engine (DOC-49 & Rule 16)
// ==========================================================

#include "test_harness.hpp"
#include <filesystem>
#include "common/window_utils.hpp"
#include "input/kmbox_net.hpp"
#include "input/non_blocking_actuator.hpp"

void TestFocusInterlockHardwareSafety() {
    std::cout << "[Test FocusInterlock] Focus Interlock & KMBox Hardware Safety Invariants..." << std::endl;

    // 1. Kiem tra Two-Factor Window Validation (common::IsPoe2WindowHwnd)
    CHECK(!common::IsPoe2WindowHwnd(nullptr), "HWND nullptr phai bi tu choi");
    HWND hDesktop = GetDesktopWindow();
    CHECK(!common::IsPoe2WindowHwnd(hDesktop), "Desktop window khong duoc coi la POE2");
    HWND hConsole = GetConsoleWindow();
    if (hConsole) {
        CHECK(!common::IsPoe2WindowHwnd(hConsole), "Console window khong duoc coi la POE2");
    }

    // 2. Kiem tra KeyUp / KeyUpVk / MouseUp KHONG BI CHAN khi Window Unfocused (RCA Fix)
    KMBoxNet kmbox;
    kmbox.EnableEmulationMode(true); // Che do gia lap an toan cho test
    kmbox.SetForcedWindowFocus(0);   // Ep trang thai Unfocused (mo phong nguoi dung Alt+Tab ra Desktop)

    CHECK(!kmbox.IsGameWindowFocused(), "kmbox phai bao Unfocused khi forcedFocus = 0");

    // KeyDown & MouseDown phai bi CHAN tuyet doi de khong ro ri phim ra man hinh
    CHECK(!kmbox.KeyDownVk(0x57), "KeyDown 'W' phai bi CHAN khi unfocused");
    CHECK(!kmbox.KeyDown(0x1A), "KeyDown HID phai bi CHAN khi unfocused");
    CHECK(!kmbox.MouseDown(1), "MouseDown phai bi CHAN khi unfocused");

    // BAT BIEN COT LOI: KeyUp & MouseUp PHAI LUON THANH CONG de giai phong phan cung, khong duoc tu choi!
    CHECK(kmbox.KeyUpVk(0x57), "KeyUpVk 'W' PHAI THANH CONG khi unfocused (Chong ket phim phan cung!)");
    CHECK(kmbox.KeyUp(0x1A), "KeyUp HID PHAI THANH CONG khi unfocused");
    CHECK(kmbox.MouseUp(1), "MouseUp PHAI THANH CONG khi unfocused (Chong ket chuot!)");

    // 3. Kiem tra Tu dong nhan dien Focus Transition (true -> false) va kich hoat ReleaseAllKeys
    kmbox.SetForcedWindowFocus(1); // Mo phong game dang active
    CHECK(kmbox.IsGameWindowFocused(), "kmbox phai bao Focused khi forcedFocus = 1");

    // Nhan giu phim WASD va chuot trong luc game dang focus
    CHECK(kmbox.KeyDownVk(0x57), "KeyDown 'W' thanh cong");
    CHECK(kmbox.KeyDownVk(0x41), "KeyDown 'A' thanh cong");
    CHECK(kmbox.MouseDown(1), "MouseDown LMB thanh cong");
    CHECK(kmbox.IsVkKeyHeld(0x57), "Phim 'W' dang duoc ghi nhan giu trong KMBox");
    CHECK(kmbox.IsVkKeyHeld(0x41), "Phim 'A' dang duoc ghi nhan giu trong KMBox");
    CHECK((kmbox.GetHeldMouseButtons() & 1) != 0, "Chuot trai dang duoc ghi nhan giu trong KMBox");

    // Nguoi dung dot ngot Alt+Tab sang Desktop / IDE / Trinh duyet (Chuyen focus thanh 0)
    kmbox.SetForcedWindowFocus(0);
    // Nhiep tick tiep theo kiem tra focus -> Tu dong phat hien transition va goi ReleaseAllKeys!
    CHECK(!kmbox.IsGameWindowFocused(), "IsGameWindowFocused phai tra ve false");

    // Kiem tra tat ca phim va chuot da duoc cuong che giai phong tu dong
    CHECK(!kmbox.IsVkKeyHeld(0x57), "Phim 'W' phai tu dong DUOC NHA ngay khi mat focus");
    CHECK(!kmbox.IsVkKeyHeld(0x41), "Phim 'A' phai tu dong DUOC NHA ngay khi mat focus");
    CHECK(kmbox.GetHeldMouseButtons() == 0, "Chuot phai tu dong DUOC NHA ngay khi mat focus");

    // 4. Kiem tra Dong bo NonBlockingActuator khi mat Focus
    kmbox.SetForcedWindowFocus(1);
    kmbox.ClearActionHistory();
    input::NonBlockingActuator actuator(kmbox);

    // Len lich 3 phim dwell dai (1000ms) tai t=1000
    actuator.KeyPressVk(0x57, 1000, 1000); // 'W'
    actuator.KeyPressVk(0x44, 1000, 1000); // 'D'
    actuator.ClickMouse(1, 1000, 1000);    // LMB
    CHECK(actuator.ActiveSlotCount() == 3, "Actuator phai co 3 slots active");
    CHECK(kmbox.IsVkKeyHeld(0x57), "KMBox phai dang giu 'W'");

    // Mat focus tai t=1010 (truoc thoi han 2000ms rat lau!)
    kmbox.SetForcedWindowFocus(0);

    // Chu trinh 120Hz goi ProcessPendingReleases tai t=1010
    actuator.ProcessPendingReleases(1010);

    // Actuator phai lap tuc giai phong sach ca 3 slots va cuong che ReleaseAllKeys phan cung
    CHECK(actuator.ActiveSlotCount() == 0, "Actuator phai clear sach slots ngay khi phat hien mat focus");
    CHECK(!kmbox.IsVkKeyHeld(0x57), "KMBox 'W' phai duoc giai phong ve false");
    CHECK(!kmbox.IsVkKeyHeld(0x44), "KMBox 'D' phai duoc giai phong ve false");
    CHECK(kmbox.GetHeldMouseButtons() == 0, "KMBox chuot phai duoc giai phong ve 0");

    // Phuc hoi lai ignore window focus de khong anh huong cac test sau
    kmbox.SetIgnoreWindowFocus(true);
    std::cout << "  -> Focus Interlock & KMBox Hardware Safety Invariants OK" << std::endl;
}

void TestWindowUtilsWin32Helpers() {
    std::cout << "[Test WindowUtils] Win32 Window & Process Utilities..." << std::endl;

    // 1. Kiem tra Win32 Helper: IsMutexActive
    const std::wstring testMutexName = L"AutoPOE2_Test_Deconflict_Mutex_" + std::to_wstring(GetCurrentProcessId());
    CHECK(!common::IsMutexActive(testMutexName), "Mutex chua tao phai tra ve false");

    HANDLE hTestMutex = CreateMutexW(nullptr, TRUE, testMutexName.c_str());
    CHECK(hTestMutex != nullptr, "CreateMutexW phai thanh cong");
    CHECK(common::IsMutexActive(testMutexName), "Mutex dang giu phai tra ve true qua IsMutexActive");

    if (hTestMutex) {
        CloseHandle(hTestMutex);
    }
    CHECK(!common::IsMutexActive(testMutexName), "Mutex da dong phai tra ve false qua IsMutexActive");
    CHECK(!common::IsMutexActive(L""), "Mutex ten rong phai tra ve false");

    // 2. Kiem tra Win32 Helper: IsProcessRunning
    CHECK(!common::IsProcessRunning(L"NonExistent_Dummy_Process_99999.exe"), "Tien trinh ao khong ton tai phai tra ve false");
    CHECK(common::IsProcessRunning(L"explorer.exe"), "explorer.exe tren Windows phai dang chay");
    CHECK(!common::IsProcessRunning(L""), "Tien trinh ten rong phai tra ve false");

    // 3. Kiem tra GetExecutableDirectory
    std::wstring exeDir = common::GetExecutableDirectory();
    CHECK(!exeDir.empty(), "GetExecutableDirectory khong duoc rong");
    CHECK(std::filesystem::exists(exeDir), "Thu muc chua binary phai ton tai tren he thong file");

    // 4. Kiem tra GetDpiScale voi nullptr (fallback mac dinh 1.0f)
    CHECK(common::GetDpiScale(nullptr) == 1.0f, "GetDpiScale(nullptr) phai tra ve 1.0f");

    // 5. Kiem tra EnsurePoe2WindowFocus o che do Bypass / Dev Mode
    KMBoxNet kmbox;
    kmbox.SetIgnoreWindowFocus(true);
    CHECK(common::EnsurePoe2WindowFocus(100), "EnsurePoe2WindowFocus phai tra ve true khi ignore window focus dang bat");
    kmbox.SetIgnoreWindowFocus(false);

    // 6. Kiem tra Focus Interlock & KMBox Hardware Safety (RCA Fix)
    TestFocusInterlockHardwareSafety();

    std::cout << "  -> WindowUtils Win32 Helpers & Focus Interlock Invariants OK" << std::endl;
}
