#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <cstdint>
#include <string>
#include <vector>

#include "common/protocol.hpp"
#include "input/kmbox_net.hpp"
#include "input/human_curve.hpp"
#include "brain/bot_brain.hpp"

// ==========================================================
// AutoPOE2 - InventoryHandler (Doc 29 - SPEC P3)
// Quản lý FSM Stash & Vendor Opcode (3500/3400) tại Town/Hideout
// ==========================================================

enum class StashFsmState : uint8_t {
    Idle = 0,
    OpenPanels = 1,       // Mở túi đồ (phím I) và click mở Stash
    SelectTab = 2,        // Chọn Tab hòm đồ theo cấu hình
    DepositItems = 3,     // Chuyển đồ từ túi vào hòm (Ctrl + Click)
    ClosePanels = 4,      // Đóng toàn bộ panel (phím Space / Esc)
    Completed = 5,
    Failed = 6
};

inline const char* StashFsmStateToString(StashFsmState state) {
    switch (state) {
        case StashFsmState::Idle: return "Idle";
        case StashFsmState::OpenPanels: return "OpenPanels";
        case StashFsmState::SelectTab: return "SelectTab";
        case StashFsmState::DepositItems: return "DepositItems";
        case StashFsmState::ClosePanels: return "ClosePanels";
        case StashFsmState::Completed: return "Completed";
        case StashFsmState::Failed: return "Failed";
        default: return "Unknown";
    }
}

enum class VendorFsmState : uint8_t {
    Idle = 0,
    ApproachNpc = 1,      // Di chuyển lại gần NPC Vendor / Salvage
    OpenVendor = 2,       // Click mở giao diện Vendor
    SellOrSalvage = 3,    // Bán hoặc rã đồ
    ClosePanels = 4,      // Đóng panel
    Completed = 5,
    Failed = 6
};

inline const char* VendorFsmStateToString(VendorFsmState state) {
    switch (state) {
        case VendorFsmState::Idle: return "Idle";
        case VendorFsmState::ApproachNpc: return "ApproachNpc";
        case VendorFsmState::OpenVendor: return "OpenVendor";
        case VendorFsmState::SellOrSalvage: return "SellOrSalvage";
        case VendorFsmState::ClosePanels: return "ClosePanels";
        case VendorFsmState::Completed: return "Completed";
        case VendorFsmState::Failed: return "Failed";
        default: return "Unknown";
    }
}

// Bảng định danh Tab Stash chuẩn trong Path of Exile 2 (Doc 63)
enum class StashTabType : uint32_t {
    Currency = 0,    // Tab 0: Currency (Orbs, Shards, Runes, Cores)
    Waystones = 1,   // Tab 1: Waystones (Tier 1-16) & Precursor Tablets
    Gems = 2,        // Tab 2: Uncut Gems & Leveling Gems
    DumpGear = 3,    // Tab 3: Rare/Unique Gear chờ thẩm định / trade
    Custom = 4
};

struct UiPoint {
    float x = 0.0f;
    float y = 0.0f;
};

struct InventoryCoordinates {
    float refWidth = 1920.0f;
    float refHeight = 1080.0f;

    // Lưới Inventory
    float invOriginX = 1272.0f;
    float invOriginY = 590.0f;
    float invCellW = 52.5f;
    float invCellH = 52.5f;
    float invOffsetX = 52.5f;
    float invOffsetY = 52.5f;
    int invCols = 12;
    int invRows = 5;

    // Lưới Stash
    float stashOriginX = 180.0f;
    float stashOriginY = 190.0f;
    float stashCellW = 52.0f;
    float stashCellH = 52.0f;
    float stashOffsetX = 52.0f;
    float stashOffsetY = 52.0f;
    int stashCols = 12;
    int stashRows = 12;

    // Tabs
    float tabStartX = 180.0f;
    float tabStartY = 140.0f;
    float tabSpacingX = 70.0f;
    int tabCount = 10;

    // Vendor
    float vendorSellTabX = 420.0f;
    float vendorSellTabY = 140.0f;
    float vendorAcceptX = 560.0f;
    float vendorAcceptY = 820.0f;
    float closeButtonX = 1860.0f;
    float closeButtonY = 60.0f;

    // Timings
    uint32_t stepDelayMs = 350;
    uint32_t itemTransferDelayMs = 180;
    uint32_t jitterMs = 50;

    UiPoint GetInventoryCell(int col, int row, [[maybe_unused]] float screenW, float screenH) const {
        const float scale = (screenH > 0.0f) ? (static_cast<float>(screenH) / 1080.0f) : 1.0f;
        float rawX = invOriginX + static_cast<float>(col) * invOffsetX + invCellW * 0.5f;
        float rawY = invOriginY + static_cast<float>(row) * invOffsetY + invCellH * 0.5f;
        return { rawX * scale, rawY * scale };
    }

    UiPoint GetStashTab(int tabIndex, [[maybe_unused]] float screenW, float screenH) const {
        const float scale = (screenH > 0.0f) ? (static_cast<float>(screenH) / 1080.0f) : 1.0f;
        float rawX = tabStartX + static_cast<float>(tabIndex) * tabSpacingX;
        float rawY = tabStartY;
        return { rawX * scale, rawY * scale };
    }

    UiPoint ScalePoint(float rawX, float rawY, [[maybe_unused]] float screenW, float screenH) const {
        const float scale = (screenH > 0.0f) ? (static_cast<float>(screenH) / 1080.0f) : 1.0f;
        return { rawX * scale, rawY * scale };
    }
};

class InventoryHandler : public IActionHandler {
public:
    InventoryHandler();

    // IActionHandler interface (BotBrain Arbiter P0)
    const char* Name() const override { return "InventoryHandler"; }
    ActionProposal Propose(const TelemetryPacket& packet, uint64_t nowMs) override;
    bool Execute(const ActionProposal& chosen, const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs) override;

    bool LoadCoordinates(const std::string& tomlPath);
    bool StartStash(const CommandPacket& cmd, uint64_t nowMs);
    bool StartVendor(const CommandPacket& cmd, uint64_t nowMs);
    void Reset();

    bool IsBusy() const {
        return (m_stashState != StashFsmState::Idle && m_stashState != StashFsmState::Completed && m_stashState != StashFsmState::Failed) ||
               (m_vendorState != VendorFsmState::Idle && m_vendorState != VendorFsmState::Completed && m_vendorState != VendorFsmState::Failed);
    }
    bool IsActive() const { return IsBusy(); }

    StashFsmState CurrentStashState() const { return m_stashState; }
    VendorFsmState CurrentVendorState() const { return m_vendorState; }
    const InventoryCoordinates& Coordinates() const { return m_coords; }
    void SetCoordinates(const InventoryCoordinates& coords) { m_coords = coords; }

    uint32_t ItemsTransferredCount() const { return m_itemsTransferred; }
    void SetItemsToTransfer(int count) { m_maxItemsToTransfer = count; }
    void SetReserveRow0(bool reserve) { m_reserveRow0 = reserve; }
    bool ReserveRow0() const { return m_reserveRow0; }

private:
    bool AdvanceStashFsm(const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs);
    bool AdvanceVendorFsm(const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs);
    bool IsSafeTownZone(const TelemetryPacket& packet) const;

    InventoryCoordinates m_coords;
    StashFsmState m_stashState = StashFsmState::Idle;
    VendorFsmState m_vendorState = VendorFsmState::Idle;
    bool m_reserveRow0 = true; // Bất biến INV-INVENTORY-ROW0-RESERVED: Giữ nguyên Hàng 1 (Row 0) cho Waystones/Tablets

    CommandPacket m_activeCmd{};
    uint64_t m_routineStartMs = 0;
    uint64_t m_lastStepMs = 0;

    int m_currentCol = 0;
    int m_currentRow = 0;
    uint32_t m_itemsTransferred = 0;
    int m_maxItemsToTransfer = 10;
    uint32_t m_targetTab = 0;
    HumanCurveGenerator m_curveGen;
};
