#include "navigation/town_quest_engine.hpp"
#include "common/logger.hpp"
#include "common/window_utils.hpp"

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <iostream>
#include <thread>
#include <chrono>

bool TownQuestEngine::FocusGameWindow() {
    return EnsurePoe2WindowFocus();
}

TownQuestEngine::TownQuestEngine(TownQuestConfig config)
    : m_config(config) {}

void TownQuestEngine::CloseMapIfOpen(KMBoxNet* kmbox) {
    if (!IsMapOpen() && m_state == TownQuestState::IDLE) {
        return;
    }
    KMBoxNet* k = kmbox ? kmbox : m_kmbox;
    const std::string msg = "[TownQuestEngine] >> Đóng giao diện World Map (gửi phím ESC / VK_ESCAPE) tránh kẹt màn hình <<";
    std::cout << msg << std::endl;
    CoreLog(msg);

    if (k) {
        SendKey(VK_ESCAPE, *k, 50);
    } else {
        if (EnsurePoe2WindowFocus()) {
            keybd_event(VK_ESCAPE, 0, 0, 0);
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
            keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
        }
    }
    m_mapOpen = false;
}

void TownQuestEngine::Reset(KMBoxNet* kmbox) {
    if (IsMapOpen()) {
        CloseMapIfOpen(kmbox ? kmbox : m_kmbox);
    }
    m_state = TownQuestState::IDLE;
    m_stateStartMs = 0;
    m_lastActionMs = 0;
    m_retryCount = 0;
    m_mapOpen = false;
    // Lưu ý: Không xóa m_currentAreaName để giữ ngữ cảnh map hiện tại sau khi travel xong
}

std::string TownQuestEngine::GetZoneName(uint32_t act, uint32_t zoneIndex) const {
    if (act == 1) {
        switch (zoneIndex) {
        case 0: return "The Riverbank";
        case 1: return "The Ogham Farmlands";
        case 2: return "The Hunting Grounds";
        default: return "The Crypt";
        }
    } else if (act == 2) {
        switch (zoneIndex) {
        case 0: return "Vastiri Outskirts";
        case 1: return "The Mastodon Sands";
        case 2: return "The Traitor's Passage";
        default: return "Dreadnought";
        }
    } else if (act == 3) {
        switch (zoneIndex) {
        case 0: return "Sandswept Marsh";
        case 1: return "Phrey Jungle";
        case 2: return "The Pools of Chakhir";
        default: return "Aggorat / Temple of Kopec";
        }
    }
    return "Zone #" + std::to_string(zoneIndex);
}

void TownQuestEngine::StartTravel(uint32_t act, uint32_t zoneIndex, uint64_t nowMs) {
    const uint32_t targetAct = (act >= 1 && act <= 3) ? act : 2;
    const std::string zoneName = GetZoneName(targetAct, zoneIndex);

    // 0. INTERLOCK: Neu dang o Hideout, tuyet doi khong mo World Map Campaign Act 1-3
    std::string curLower = m_currentAreaName;
    for (char& c : curLower) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
    if (curLower.find("hideout") != std::string::npos && targetAct <= 3) {
        const std::string msg = "[TownQuestEngine] >> Nhan vat dang o Hideout ('" + m_currentAreaName + "')! Tu choi bam phim U di Campaign Act " + std::to_string(targetAct) + ". <<";
        std::cout << "\n" << msg << std::endl;
        CoreLog(msg);
        return;
    }

    // 1. Kiểm tra nếu nhân vật đã ở đúng map đó rồi: bỏ qua để tránh spam phím U
    if (!m_currentAreaName.empty() && 
        (m_currentAreaName == zoneName || 
         m_currentAreaName.find(zoneName) != std::string::npos || 
         zoneName.find(m_currentAreaName) != std::string::npos)) {
        const std::string msg = "[TownQuestEngine] >> Nhân vật đang ở đúng map '" + zoneName + "' rồi! Bỏ qua lệnh travel để tránh spam phím U. <<";
        std::cout << "\n" << msg << std::endl;
        CoreLog(msg);
        return;
    }

    // 2. Kiểm tra nếu đang trong chu kỳ bấm phím U / mở map hoặc đang dịch chuyển tới cùng đích:
    // tránh spam phím U liên tục làm đóng/mở giao diện World Map
    if (IsActive()) {
        if (m_targetAct == targetAct && m_targetZoneIndex == zoneIndex) {
            const std::string msg = "[TownQuestEngine] >> Đang trong chu kỳ dịch chuyển tới Act " + std::to_string(targetAct)
                + " (" + zoneName + ")! Bỏ qua lệnh trùng lặp để tránh spam phím U. <<";
            std::cout << "\n" << msg << std::endl;
            CoreLog(msg);
            return;
        }

        if (m_state == TownQuestState::PRESS_U || m_state == TownQuestState::WAIT_MAP_OPEN) {
            const std::string msg = "[TownQuestEngine] >> Đang trong chu kỳ bấm U mở giao diện World Map (State="
                + std::to_string(static_cast<uint32_t>(m_state)) + ")! Bỏ qua lệnh mới để tránh đóng/mở giao diện. <<";
            std::cout << "\n" << msg << std::endl;
            CoreLog(msg);
            return;
        }
    }

    m_targetAct = targetAct;
    m_targetZoneIndex = zoneIndex;
    m_state = TownQuestState::PRESS_U;
    m_stateStartMs = nowMs;
    m_lastActionMs = nowMs;
    m_retryCount = 0;

    const std::string msg = "[TownQuestEngine] >> KÍCH HOẠT DỊCH CHUYỂN WORLD MAP (PHÍM U): Act "
        + std::to_string(m_targetAct) + " (" + zoneName + ") <<";
    std::cout << "\n" << msg << std::endl;
    CoreLog(msg);
}

void TownQuestEngine::OnLoadingFinished(const std::string& areaName, uint64_t /*nowMs*/) {
    m_currentAreaName = areaName;
    if (IsActive()) {
        const std::string msg = "[TownQuestEngine] >> ĐÃ VÀO PHỤ BẢN MỚI: "
            + areaName + ". Bàn giao quyền điều khiển cho Combat & Zone Runner! <<";
        std::cout << "\n" << msg << std::endl;
        CoreLog(msg);
        m_mapOpen = false;
        m_state = TownQuestState::IDLE;
        m_stateStartMs = 0;
        m_lastActionMs = 0;
        m_retryCount = 0;
    }
}



bool TownQuestEngine::GetGameWindowRect(int& outLeft, int& outTop, int& outWidth, int& outHeight) {
    HWND hwnd = FindPoe2Window();

    if (hwnd) {
        RECT rc{};
        if (GetWindowRect(hwnd, &rc)) {
            outLeft = rc.left;
            outTop = rc.top;
            outWidth = rc.right - rc.left;
            outHeight = rc.bottom - rc.top;
            if (outWidth > 100 && outHeight > 100) {
                return true;
            }
        }
    }

    // Fallback: Lấy độ phân giải toàn màn hình
    outLeft = 0;
    outTop = 0;
    outWidth = GetSystemMetrics(SM_CXSCREEN);
    outHeight = GetSystemMetrics(SM_CYSCREEN);
    if (outWidth <= 0) outWidth = 1920;
    if (outHeight <= 0) outHeight = 1080;
    return false;
}

void TownQuestEngine::SendClick(int x, int y, KMBoxNet& kmbox) {
    if (!EnsurePoe2WindowFocus()) return;
    kmbox.MoveMouseSmooth(x, y, m_curveGen, 15, 1);
    kmbox.ClickMouseHumanized(1, m_curveGen, 50.0f, 10.0f);
}

void TownQuestEngine::SendDoubleClick(int x, int y, KMBoxNet& kmbox) {
    if (!EnsurePoe2WindowFocus()) return;
    kmbox.MoveMouseSmooth(x, y, m_curveGen, 15, 1);
    kmbox.ClickMouseHumanized(1, m_curveGen, 45.0f, 8.0f);
    std::this_thread::sleep_for(std::chrono::milliseconds(70));
    kmbox.ClickMouseHumanized(1, m_curveGen, 45.0f, 8.0f);
}

void TownQuestEngine::SendKey(uint8_t vk, KMBoxNet& kmbox, uint32_t holdMs) {
    if (!EnsurePoe2WindowFocus()) return;
    if (kmbox.IsEmulationMode()) {
        keybd_event(vk, 0, 0, 0);
        std::this_thread::sleep_for(std::chrono::milliseconds(holdMs));
        keybd_event(vk, 0, KEYEVENTF_KEYUP, 0);
    } else {
        uint8_t hid = vk;
        if (vk == VK_RETURN) hid = 0x28;
        else if (vk == 0x55) hid = 0x18; // 'U' HID code = 0x18
        else if (vk == VK_SPACE) hid = 0x2C;
        else if (vk == VK_ESCAPE) hid = 0x29;

        kmbox.KeyPress(hid, holdMs);
    }
}

bool TownQuestEngine::Tick(KMBoxNet& kmbox, uint64_t nowMs) {
    m_kmbox = &kmbox;
    if (m_state == TownQuestState::IDLE) return false;
    if (!EnsurePoe2WindowFocus()) return false;

    switch (m_state) {
    case TownQuestState::PRESS_U: {
        // Bảo vệ chống spam phím U trong khoảng thời gian quá ngắn (< 500ms)
        if (m_lastUKeyMs > 0 && nowMs - m_lastUKeyMs < 500) {
            return false;
        }
        FocusGameWindow();
        // Phím U: Virtual Key = 0x55
        SendKey(0x55, kmbox, 50);
        m_lastUKeyMs = nowMs;
        m_mapOpen = true;

        const std::string msg = "[TownQuestEngine] >> Đã bấm phím 'U' (0x55) mở giao diện World Map POE2 <<";
        std::cout << msg << std::endl;
        CoreLog(msg);

        m_state = TownQuestState::WAIT_MAP_OPEN;
        m_stateStartMs = nowMs;
        m_lastActionMs = nowMs;
        return true;
    }

    case TownQuestState::WAIT_MAP_OPEN: {
        if (nowMs - m_stateStartMs >= m_config.mapOpenDelayMs) {
            m_state = TownQuestState::CLICK_ACT_TAB;
            m_stateStartMs = nowMs;
            m_lastActionMs = nowMs;
            return true;
        }
        break;
    }

    case TownQuestState::CLICK_ACT_TAB: {
        FocusGameWindow();
        int left = 0, top = 0, width = 0, height = 0;
        GetGameWindowRect(left, top, width, height);

        // Vị trí Tab Act trên đỉnh màn hình World Map POE2
        // Act 1: 38%, Act 2: 50%, Act 3: 62% (Y = 12%)
        float tabNormX = 0.50f;
        if (m_targetAct == 1) tabNormX = 0.38f;
        else if (m_targetAct == 2) tabNormX = 0.50f;
        else if (m_targetAct == 3) tabNormX = 0.62f;

        int tabX = left + static_cast<int>(width * tabNormX);
        int tabY = top + static_cast<int>(height * 0.12f);

        SendClick(tabX, tabY, kmbox);

        const std::string msg = "[TownQuestEngine] >> Đã click chọn Tab Act "
            + std::to_string(m_targetAct) + " tại (" + std::to_string(tabX) + ", " + std::to_string(tabY) + ") <<";
        std::cout << msg << std::endl;
        CoreLog(msg);

        m_state = TownQuestState::CLICK_ZONE_NODE;
        m_stateStartMs = nowMs;
        m_lastActionMs = nowMs;
        return true;
    }

    case TownQuestState::CLICK_ZONE_NODE: {
        if (nowMs - m_stateStartMs >= m_config.tabSwitchDelayMs) {
            FocusGameWindow();
            int left = 0, top = 0, width = 0, height = 0;
            GetGameWindowRect(left, top, width, height);

            float zoneNormX = 0.50f;
            float zoneNormY = 0.50f;
            std::string zoneName = "Phụ bản #" + std::to_string(m_targetZoneIndex);

            if (m_targetAct == 1) {
                switch (m_targetZoneIndex) {
                case 0: zoneNormX = 0.32f; zoneNormY = 0.65f; zoneName = "The Riverbank"; break;
                case 1: zoneNormX = 0.42f; zoneNormY = 0.55f; zoneName = "The Ogham Farmlands"; break;
                case 2: zoneNormX = 0.52f; zoneNormY = 0.50f; zoneName = "The Hunting Grounds"; break;
                default: zoneNormX = 0.60f; zoneNormY = 0.45f; zoneName = "The Crypt"; break;
                }
            } else if (m_targetAct == 2) {
                switch (m_targetZoneIndex) {
                case 0: zoneNormX = 0.40f; zoneNormY = 0.62f; zoneName = "Vastiri Outskirts"; break;
                case 1: zoneNormX = 0.52f; zoneNormY = 0.52f; zoneName = "The Mastodon Sands"; break;
                case 2: zoneNormX = 0.58f; zoneNormY = 0.46f; zoneName = "The Traitor's Passage"; break;
                default: zoneNormX = 0.68f; zoneNormY = 0.42f; zoneName = "Dreadnought"; break;
                }
            } else if (m_targetAct == 3) {
                switch (m_targetZoneIndex) {
                case 0: zoneNormX = 0.36f; zoneNormY = 0.60f; zoneName = "Sandswept Marsh"; break;
                case 1: zoneNormX = 0.48f; zoneNormY = 0.52f; zoneName = "Phrey Jungle"; break;
                case 2: zoneNormX = 0.58f; zoneNormY = 0.45f; zoneName = "The Pools of Chakhir"; break;
                default: zoneNormX = 0.68f; zoneNormY = 0.38f; zoneName = "Aggorat / Temple of Kopec"; break;
                }
            } else {
                zoneNormX = 0.48f; zoneNormY = 0.55f;
            }

            int zoneX = left + static_cast<int>(width * zoneNormX);
            int zoneY = top + static_cast<int>(height * zoneNormY);

            // Double-click vào Node bản đồ (cơ chế dịch chuyển nhanh trong POE2 World Map)
            SendDoubleClick(zoneX, zoneY, kmbox);

            const std::string msg = "[TownQuestEngine] >> Đã click chọn Node Map: " + zoneName
                + " (Act " + std::to_string(m_targetAct) + ", #" + std::to_string(m_targetZoneIndex)
                + ") tại (" + std::to_string(zoneX) + ", " + std::to_string(zoneY) + ") <<";
            std::cout << msg << std::endl;
            CoreLog(msg);

            m_state = TownQuestState::CONFIRM_TRAVEL;
            m_stateStartMs = nowMs;
            m_lastActionMs = nowMs;
            return true;
        }
        break;
    }

    case TownQuestState::CONFIRM_TRAVEL: {
        if (nowMs - m_stateStartMs >= m_config.zoneClickDelayMs) {
            FocusGameWindow();
            int left = 0, top = 0, width = 0, height = 0;
            GetGameWindowRect(left, top, width, height);

            // 1. Click nút "Travel" tại khu vực cạnh dưới bản đồ (50% X, 88% Y)
            int travelBtnX = left + static_cast<int>(width * 0.50f);
            int travelBtnY = top + static_cast<int>(height * 0.88f);
            SendClick(travelBtnX, travelBtnY, kmbox);

            // 2. Gửi thêm phím Enter (VK_RETURN) dự phòng xác nhận dịch chuyển vào Instance
            SendKey(VK_RETURN, kmbox, 45);

            const std::string msg = "[TownQuestEngine] >> Đã click nút 'Travel' tại (" + std::to_string(travelBtnX) + ", "
                + std::to_string(travelBtnY) + ") & gửi phím Enter xác nhận dịch chuyển! Chờ màn hình tải map... <<";
            std::cout << msg << std::endl;
            CoreLog(msg);

            m_state = TownQuestState::WAIT_ZONE_LOAD;
            m_stateStartMs = nowMs;
            m_lastActionMs = nowMs;
            return true;
        }
        break;
    }

    case TownQuestState::WAIT_ZONE_LOAD: {
        if (nowMs - m_stateStartMs >= m_config.maxLoadWaitMs) {
            const std::string msg = "[TownQuestEngine] >> Hết thời gian chờ tải map ("
                + std::to_string(m_config.maxLoadWaitMs) + "ms). Đóng giao diện World Map (ESC) và đặt lại trạng thái. <<";
            std::cout << msg << std::endl;
            CoreLog(msg);
            CloseMapIfOpen(&kmbox);
            Reset(&kmbox);
            return true;
        }
        break;
    }

    default:
        break;
    }

    return false;
}
