#include "brain/npc_interaction_handler.hpp"

#include <fstream>
#include <iostream>
#include <sstream>
#include <cmath>
#include "common/logger.hpp"
#include "common/window_utils.hpp"
#include "common/toml_parser.hpp"
#include "common/coordinate_transform.hpp"

namespace {

using common::ParseTomlFloat;
using common::ParseTomlUint;

static bool EnsureWindowFocus() {
    if (KMBoxNet::IsAnyIgnoreWindowFocus()) return true;
    HWND hwnd = common::FindPoe2Window();
    if (!hwnd) return false;
    return (GetForegroundWindow() == hwnd);
}

} // namespace

NpcInteractionHandler::NpcInteractionHandler() {
    LoadCoordinates("data/ui/coordinates.toml");
}

bool NpcInteractionHandler::LoadCoordinates(const std::string& tomlPath) {
    std::ifstream file(tomlPath);
    if (!file.is_open()) {
        CoreLog("[NpcInteractionHandler] Khong the mo file toa do: " + tomlPath + ". Dung toa do mac dinh 1080p.");
        return false;
    }

    std::string line;
    std::string currentSection;

    while (std::getline(file, line)) {
        size_t first = line.find_first_not_of(" \t\r\n");
        if (first == std::string::npos || line[first] == '#' || line[first] == ';') {
            continue;
        }

        if (line[first] == '[') {
            size_t last = line.find(']', first);
            if (last != std::string::npos) {
                currentSection = line.substr(first + 1, last - first - 1);
            }
            continue;
        }

        if (currentSection == "screen") {
            ParseTomlFloat(line, "reference_width", m_coords.refWidth);
            ParseTomlFloat(line, "reference_height", m_coords.refHeight);
        } else if (currentSection == "npc_dialogue") {
            ParseTomlFloat(line, "dialogue_menu_x", m_coords.dialogueMenuX);
            ParseTomlFloat(line, "dialogue_menu_y", m_coords.dialogueMenuY);
            ParseTomlFloat(line, "dialogue_option_height", m_coords.dialogueOptionHeight);
            ParseTomlFloat(line, "identify_all_x", m_coords.identifyAllX);
            ParseTomlFloat(line, "identify_all_y", m_coords.identifyAllY);
        } else if (currentSection == "delays") {
            ParseTomlUint(line, "default_step_delay_ms", m_coords.stepDelayMs);
            ParseTomlUint(line, "jitter_ms", m_coords.jitterMs);
        }
    }

    return true;
}

bool NpcInteractionHandler::StartInteract(const CommandPacket& cmd, uint64_t nowMs) {
    uint32_t npcId = cmd.targetEntityId;
    auto mode = static_cast<NpcInteractMode>(static_cast<uint32_t>(cmd.targetX));
    uint32_t optionIdx = static_cast<uint32_t>(cmd.targetY);
    m_timeoutMs = (cmd.timeoutMs > 0) ? cmd.timeoutMs : 15000;
    return StartInteract(npcId, mode, optionIdx, nowMs);
}

bool NpcInteractionHandler::StartInteract(uint32_t npcEntityId, NpcInteractMode mode, uint32_t optionIdx, uint64_t nowMs) {
    m_targetNpcId = npcEntityId;
    m_mode = mode;
    m_optionIndex = optionIdx;
    m_routineStartMs = nowMs;
    m_lastStepMs = nowMs;
    m_state = NpcInteractState::ApproachNpc;
    m_targetNpcName = "";

    std::string msg = "[NpcInteractionHandler] Start NPC interact (TargetId=" + std::to_string(npcEntityId) +
                      ", Mode=" + std::string(NpcInteractModeToString(mode)) +
                      ", Option=" + std::to_string(optionIdx) + ")";
    std::cout << msg << std::endl;
    CoreLog(msg);
    return true;
}

void NpcInteractionHandler::Reset() {
    m_state = NpcInteractState::Idle;
    m_targetNpcId = 0;
    m_targetNpcName = "";
    m_routineStartMs = 0;
}

bool NpcInteractionHandler::IsSafeZone(const TelemetryPacket& packet) const {
    const auto& player = packet.player;
    for (uint32_t i = 0; i < packet.entityCount; ++i) {
        const auto& ent = packet.entities[i];
        if (ent.type == 1 && !(ent.extraFlags & 4) && ent.currentHP > 0) {
            const float dx = ent.posX - player.posX;
            const float dy = ent.posY - player.posY;
            const float dist = std::sqrt(dx * dx + dy * dy);
            if (dist <= 350.0f) {
                return false; // Có quái vật sống trong tầm giao tranh
            }
        }
    }
    return true;
}

int NpcInteractionHandler::FindCandidateNpcIndex(const TelemetryPacket& packet) const {
    const auto& player = packet.player;
    int bestIdx = -1;
    float bestDist = 9999.0f;

    for (uint32_t i = 0; i < packet.entityCount; ++i) {
        const auto& ent = packet.entities[i];
        if (ent.type != 4 && ent.type != 3) continue; // Phải là NPC (4) hoặc đối tượng tương tác (3)
        if (ent.extraFlags & 4) continue; // Bỏ qua thực thể đã chết

        if (m_targetNpcId != 0 && ent.id == m_targetNpcId) {
            return static_cast<int>(i);
        }

        // Nếu m_targetNpcId == 0: tìm NPC phù hợp theo Mode
        if (m_targetNpcId == 0 && ent.type == 4) {
            NpcRole role = ClassifyNpcRole(ent.name);
            bool match = false;
            if (m_mode == NpcInteractMode::IdentifyAll && role == NpcRole::Identifier) match = true;
            else if (m_mode == NpcInteractMode::OpenCurrencyExchange && role == NpcRole::CurrencyExchange) match = true;
            else if (m_mode == NpcInteractMode::OpenVendor && (role == NpcRole::Vendor || role == NpcRole::QuestGiver)) match = true;
            else if (m_mode == NpcInteractMode::TalkAndSkip) match = true;

            const float dx = ent.posX - player.posX;
            const float dy = ent.posY - player.posY;
            const float dist = std::sqrt(dx * dx + dy * dy);

            if (match && dist < bestDist) {
                bestDist = dist;
                bestIdx = static_cast<int>(i);
            }
        }
    }

    return bestIdx;
}

ActionProposal NpcInteractionHandler::Propose(const TelemetryPacket& packet, uint64_t nowMs) {
    if (!IsActive()) return {};

    // 1. Kiểm tra timeout
    if (m_routineStartMs > 0 && (nowMs - m_routineStartMs > m_timeoutMs)) {
        m_state = NpcInteractState::Failed;
        CoreLog("[NpcInteractionHandler] Routine TIMEOUT (" + std::to_string(m_timeoutMs) + "ms)!");
        return {};
    }

    // 2. Bất biến an toàn INV-NPC-01: Nếu có quái vật xuất hiện -> Hủy FSM (Fail-Closed)
    if (!IsSafeZone(packet)) {
        m_state = NpcInteractState::Failed;
        CoreLog("[NpcInteractionHandler] INV-NPC-01 Violated: Live monster in area! Aborting NPC interact.");
        return {};
    }

    // 3. Đề xuất hành động NPC_INTERACT với priority 3300
    ActionProposal p{};
    p.kind = BotActionKind::NpcInteract;
    p.priority = bot_priority::NPC_INTERACT; // 3300
    p.priorityName = "NPC_INTERACT";
    p.entityId = m_targetNpcId;
    return p;
}

bool NpcInteractionHandler::Execute(const ActionProposal& chosen, const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs) {
    if (chosen.kind != BotActionKind::NpcInteract) return false;
    return AdvanceFsm(packet, kmbox, nowMs);
}

bool NpcInteractionHandler::AdvanceFsm(const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs) {
    if (!EnsureWindowFocus()) return false;

    if (nowMs - m_lastStepMs < m_coords.stepDelayMs) {
        return true;
    }

    int actualW = GetSystemMetrics(SM_CXSCREEN);
    int actualH = GetSystemMetrics(SM_CYSCREEN);
    const float screenW = (actualW > 0) ? static_cast<float>(actualW) : 1920.0f;
    const float screenH = (actualH > 0) ? static_cast<float>(actualH) : 1080.0f;

    switch (m_state) {
        case NpcInteractState::ApproachNpc: {
            int npcIdx = FindCandidateNpcIndex(packet);
            if (npcIdx >= 0) {
                const auto& ent = packet.entities[npcIdx];
                m_targetNpcId = ent.id;
                m_targetNpcName = (ent.name[0] ? ent.name : "NPC");
            }

            m_state = NpcInteractState::OpenDialogue;
            m_lastStepMs = nowMs;
            CoreLog("[NpcInteractionHandler] State: ApproachNpc -> OpenDialogue (Target: " + m_targetNpcName + ")");
            return true;
        }

        case NpcInteractState::OpenDialogue: {
            // Trong POE2 KBM, tương tác (Interact) với NPC là Click chuột trái (LMB) lên NPC.
            // Phím 'F' là Skill 8 của người chơi, TUYỆT ĐỐI CẤM gửi phím F để mở đối thoại!
            int npcIdx = FindCandidateNpcIndex(packet);
            if (npcIdx >= 0) {
                const auto& ent = packet.entities[npcIdx];
                float dx = ent.posX - packet.player.posX;
                float dy = ent.posY - packet.player.posY;
                float worldDist = std::sqrt(dx * dx + dy * dy);
                float pixelDist = (std::min)(worldDist * 16.0f, 400.0f);
                auto screenPt = common::WorldToScreenIsometric(dx, dy, pixelDist, screenW, screenH, 80.0f);
                kmbox.MoveMouseSmooth(static_cast<int>(screenPt.x), static_cast<int>(screenPt.y), m_curveGen, 12, 1);
            }
            int dwellMs = m_curveGen.GenerateDwellTimeMs(45.0f, 8.0f);
            kmbox.ClickMouse(1, dwellMs);
            m_state = NpcInteractState::SelectOption;
            m_lastStepMs = nowMs;
            CoreLog("[NpcInteractionHandler] State: OpenDialogue -> SelectOption (Click LMB tuong tac NPC: " + m_targetNpcName + ")");
            return true;
        }

        case NpcInteractState::SelectOption: {
            if (m_mode == NpcInteractMode::IdentifyAll) {
                // Click nút "Identify All Items" của The Hooded One
                auto pt = m_coords.ScalePoint(m_coords.identifyAllX, m_coords.identifyAllY, screenW, screenH);
                kmbox.MoveMouseSmooth(static_cast<int>(pt.x), static_cast<int>(pt.y), m_curveGen, 12, 1);
                kmbox.ClickMouse(1, 35);
                CoreLog("[NpcInteractionHandler] The Hooded One: Clicked 'Identify All Items'!");
            } else if (m_mode == NpcInteractMode::TalkAndSkip) {
                // Nhấn phím Spacebar để bỏ qua hội thoại cốt truyện
                kmbox.KeyPress(VK_SPACE, 40);
                CoreLog("[NpcInteractionHandler] Skipped NPC dialogue via Spacebar");
            } else {
                // Chọn tùy chọn theo chỉ số optionIndex
                float optY = m_coords.dialogueMenuY + static_cast<float>(m_optionIndex) * m_coords.dialogueOptionHeight;
                auto pt = m_coords.ScalePoint(m_coords.dialogueMenuX, optY, screenW, screenH);
                kmbox.MoveMouseSmooth(static_cast<int>(pt.x), static_cast<int>(pt.y), m_curveGen, 12, 1);
                kmbox.ClickMouse(1, 35);
                CoreLog("[NpcInteractionHandler] Selected dialogue option index: " + std::to_string(m_optionIndex));
            }

            m_state = NpcInteractState::CloseDialogue;
            m_lastStepMs = nowMs;
            return true;
        }

        case NpcInteractState::CloseDialogue: {
            // Đóng menu hội thoại (nhấn Space/ESC)
            kmbox.KeyPress(m_coords.closeKey, 40);
            m_state = NpcInteractState::Completed;
            m_lastStepMs = nowMs;
            m_interactionsCompleted++;
            CoreLog("[NpcInteractionHandler] State: CloseDialogue -> Completed (Total: " +
                    std::to_string(m_interactionsCompleted) + ")");
            std::cout << "[NpcInteractionHandler] >> Hoàn tất tương tác với NPC: "
                      << m_targetNpcName << " <<" << std::endl;
            return true;
        }

        case NpcInteractState::Completed:
        case NpcInteractState::Failed:
        case NpcInteractState::Idle:
        default:
            return false;
    }
}
