"""AutoPOE2 - Faustus Currency Exchange Handler (Doc 43 / Doc 68 / Doc 69).
=========================================================================
Điều phối viên độc lập cho Sàn Giao Dịch Ngoại Hối Faustus Currency Exchange:
1. Mở sàn bằng phím '/' (VK_OEM_2 0xBF, scan code 0x35) chuẩn SSoT.
2. Tự động đổi Chaos Orb lấy Waystone T15 khi kho Waystone trong Stash chạm mốc 0.
3. Tuân thủ nghiêm ngặt INV-FOCUS-SAFETY-SEPARATION: Tuyệt đối không rò rỉ tín hiệu phần cứng
   ra desktop người dùng khi ở chế độ mô phỏng (is_simulated=True) hoặc khi game mất focus.
4. Đóng giao diện sàn an toàn bằng Spacebar (VK_SPACE 0x20, scan code 0x39).
5. Bảo vệ quỹ vàng sinh tồn (INV-EXCHANGE-GOLD-TAX) và quỹ Chaos dự trữ (INV-EXCHANGE-RESERVE-SAFE).
6. Tuân thủ Rule 4: Module hóa độc lập, trần file < 500 dòng.
"""

from __future__ import annotations

import time
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, Optional, Tuple

from src.common.win32_input import (
    SC_SPACE,
    VK_OEM_2,
    VK_SPACE,
    click as win32_click,
    dismiss_modals as win32_dismiss_modals,
    press_key as win32_press_key,
)
from src.common.win32_window import ensure_window_focus, is_poe2_window_focused

# Scan code cho phím '/' trên bàn phím chuẩn US QWERTY
SC_SLASH = 0x35

# Tọa độ giao diện Faustus Currency Exchange chuẩn hóa trên màn hình 2560x1440
EXCHANGE_SEARCH_INPUT_POS_2560 = (1280, 420)
EXCHANGE_CURRENCY_HAVE_POS_2560 = (920, 520)
EXCHANGE_CURRENCY_WANT_POS_2560 = (1640, 520)
EXCHANGE_CONFIRM_BTN_POS_2560 = (1280, 880)
EXCHANGE_CLOSE_BTN_POS_2560 = (1950, 180)


@dataclass
class CurrencyExchangeHandlerConfig:
    """Cấu hình an toàn và định mức vận hành Sàn Faustus."""
    min_gold_reserve: int = 5000          # Ngưỡng sàn bảo vệ Vàng (INV-EXCHANGE-GOLD-TAX)
    min_chaos_reserve: float = 50.0       # Giữ lại 50 Chaos sinh tồn/crafting (INV-EXCHANGE-RESERVE-SAFE)
    chaos_per_waystone_t15: float = 2.0   # Tỷ giá thị trường Chaos/Waystone T15 POE2 Scout
    gold_tax_per_waystone: int = 150      # Phí giao dịch Vàng dự tính cho mỗi Waystone T15
    default_buy_count: int = 5            # Số lượng Waystone T15 mua mặc định khi hết kho
    waystone_restock_threshold: int = 0   # Kích hoạt restock khi số Waystone <= ngưỡng này
    ui_open_delay_s: float = 0.25         # Thời gian chờ UI mở sau khi bấm '/'
    ui_close_delay_s: float = 0.15        # Thời gian chờ sau khi bấm Spacebar đóng UI


@dataclass
class ExchangeResult:
    """Kết quả thực thi phiên mua bán trên Sàn Faustus."""
    success: bool = False
    action_taken: str = "NONE"            # "RESTOCKED_WAYSTONES", "NO_ACTION_REQUIRED", "REJECTED_LOW_CHAOS", etc.
    waystones_bought: int = 0
    chaos_spent: float = 0.0
    gold_spent: int = 0
    remaining_chaos: float = 0.0
    remaining_gold: int = 0
    reason: str = ""
    timestamp_ms: int = 0

    def to_dict(self) -> Dict[str, Any]:
        return {
            "success": self.success,
            "action_taken": self.action_taken,
            "waystones_bought": self.waystones_bought,
            "chaos_spent": self.chaos_spent,
            "gold_spent": self.gold_spent,
            "remaining_chaos": self.remaining_chaos,
            "remaining_gold": self.remaining_gold,
            "reason": self.reason,
            "timestamp_ms": self.timestamp_ms,
        }


class CurrencyExchangeHandler:
    """
    Điều phối viên độc lập cho Sàn Faustus Currency Exchange.
    - Mở sàn bằng phím '/' (VK_OEM_2 0xBF).
    - Mua Waystone T15 bằng Chaos Orb khi kho cạn kiệt (count <= 0).
    - Đóng sàn an toàn bằng Spacebar (VK_SPACE 0x20).
    - Bảo vệ Focus Interlock chống rò rỉ phím vật lý ra desktop (INV-FOCUS-SAFETY-SEPARATION).
    """

    def __init__(
        self,
        screen_w: int = 2560,
        screen_h: int = 1440,
        config: Optional[CurrencyExchangeHandlerConfig] = None,
        is_simulated: bool = False,
        press_key_func: Optional[Callable[[int], Any]] = None,
        click_func: Optional[Callable[..., Any]] = None,
        log_callback: Optional[Callable[[str], None]] = None,
    ):
        self.screen_w = screen_w
        self.screen_h = screen_h
        self.scale_x = screen_w / 2560.0 if screen_w > 0 else 1.0
        self.scale_y = screen_h / 1440.0 if screen_h > 0 else 1.0
        self.config = config or CurrencyExchangeHandlerConfig()
        self.is_simulated = is_simulated
        self.press_key_func = press_key_func
        self.click_func = click_func
        self.log_callback = log_callback
        self.is_ui_open: bool = False
        self.total_restock_operations: int = 0

    def log(self, msg: str) -> None:
        if self.log_callback:
            self.log_callback(msg)
        else:
            print(f"[CurrencyExchangeHandler] {msg}", flush=True)

    def is_safe_area(self, area_name: str) -> bool:
        """Kiểm tra khu vực an toàn (INV-EXCHANGE-SAFE-AREA): Chỉ mở sàn tại Hideout hoặc Town."""
        lower = area_name.lower()
        return ("hideout" in lower) or ("town" in lower) or ("encampment" in lower)

    def open_currency_exchange(self) -> bool:
        """
        Mở sàn Faustus Currency Exchange bằng phím '/' (VK_OEM_2 0xBF).
        Tuân thủ Rule 7 SSoT & INV-FOCUS-SAFETY-SEPARATION.
        """
        # Kiểm tra Foreground focus nếu chạy trên môi trường thực (không phải simulation)
        if not self.is_simulated:
            if not is_poe2_window_focused():
                ensure_window_focus(timeout_ms=300)
                if not is_poe2_window_focused():
                    self.log("LỖI: Game client không có Focus. Chặn gửi phím '/' để bảo vệ desktop.")
                    return False

        # Thực thi gửi phím '/' (0xBF)
        if self.press_key_func is not None:
            self.press_key_func(VK_OEM_2)
        else:
            win32_press_key(
                vk=VK_OEM_2,
                scan=SC_SLASH,
                hold_ms=0.05,
                delay_after=self.config.ui_open_delay_s,
                is_simulated=self.is_simulated,
            )

        self.is_ui_open = True
        self.log("Đã phát phím '/' mở Faustus Currency Exchange.")
        return True

    def close_currency_exchange(self) -> bool:
        """
        Đóng sàn Faustus an toàn bằng phím Spacebar (VK_SPACE 0x20).
        Tuân thủ Rule 7 SSoT & INV-SPACEBAR-CLOSE.
        """
        if not self.is_simulated:
            if not is_poe2_window_focused():
                self.log("CẢNH BÁO: Game không giữ Focus khi đóng UI.")
                return False

        # Thực thi gửi phím Spacebar (0x20)
        if self.press_key_func is not None:
            self.press_key_func(VK_SPACE)
        else:
            win32_dismiss_modals(
                count_or_img=1,
                delay_after=self.config.ui_close_delay_s,
                is_simulated=self.is_simulated,
            )

        self.is_ui_open = False
        self.log("Đã phát phím Spacebar đóng Faustus Currency Exchange.")
        return True

    def check_restock_needed(self, waystone_stock: int) -> bool:
        """Kiểm tra xem có cần bổ sung Waystone T15 hay không (kho <= ngưỡng)."""
        return waystone_stock <= self.config.waystone_restock_threshold

    def evaluate_restock_feasibility(
        self,
        available_chaos: float,
        available_gold: int,
        target_count: int,
    ) -> Tuple[bool, int, str]:
        """
        Đánh giá tính khả thi và số lượng Waystone T15 có thể mua được:
        - Bảo vệ Chaos sinh tồn (INV-EXCHANGE-RESERVE-SAFE).
        - Bảo vệ Vàng đóng thuế (INV-EXCHANGE-GOLD-TAX).
        """
        # 1. Kiểm tra Chaos khả dụng
        usable_chaos = available_chaos - self.config.min_chaos_reserve
        if usable_chaos < self.config.chaos_per_waystone_t15:
            return (
                False,
                0,
                f"Bảo vệ Chaos Orb: Số Chaos hiện có ({available_chaos}) - ngưỡng dự trữ ({self.config.min_chaos_reserve}) "
                f"< đơn giá ({self.config.chaos_per_waystone_t15}).",
            )

        # 2. Kiểm tra Vàng khả dụng
        usable_gold = available_gold - self.config.min_gold_reserve
        if usable_gold < self.config.gold_tax_per_waystone:
            return (
                False,
                0,
                f"Bảo vệ Gold Tax: Số Vàng hiện có ({available_gold}) - ngưỡng sàn ({self.config.min_gold_reserve}) "
                f"< thuế giao dịch ({self.config.gold_tax_per_waystone}).",
            )

        # 3. Tính toán số lượng tối đa có thể mua
        max_by_chaos = int(usable_chaos // self.config.chaos_per_waystone_t15)
        max_by_gold = int(usable_gold // self.config.gold_tax_per_waystone)
        affordable_count = min(target_count, max_by_chaos, max_by_gold)

        if affordable_count <= 0:
            return False, 0, "Không đủ Chaos Orb hoặc Vàng để mua tối thiểu 1 Waystone T15."

        return True, affordable_count, "Đủ điều kiện thanh toán và nộp thuế Vàng."

    def _simulate_or_click_screen(self, normalized_pos: Tuple[int, int]) -> bool:
        """Click tọa độ co giãn theo độ phân giải."""
        screen_x = int(round(normalized_pos[0] * self.scale_x))
        screen_y = int(round(normalized_pos[1] * self.scale_y))
        if self.click_func is not None:
            return bool(self.click_func(screen_x, screen_y))
        return win32_click(screen_x, screen_y, is_simulated=self.is_simulated)

    def execute_waystone_t15_restock(
        self,
        waystone_stock: int,
        available_chaos: float,
        available_gold: int,
        buy_count: Optional[int] = None,
        area_name: str = "Shoreline Hideout",
        now_ms: Optional[int] = None,
    ) -> ExchangeResult:
        """
        Thực thi quy trình đổi Chaos Orb lấy Waystone T15 khi hết kho Stash:
        1. Kiểm tra an toàn khu vực (INV-EXCHANGE-SAFE-AREA).
        2. Kiểm tra nhu cầu restock (kho <= threshold).
        3. Đánh giá tính khả thi tài chính & thuế Vàng.
        4. Mở sàn bằng phím '/'.
        5. Thực thi giao dịch nạp đơn hàng.
        6. Đóng sàn bằng phím Spacebar.
        7. Trả về kết quả ExchangeResult.
        """
        if now_ms is None:
            now_ms = int(time.time() * 1000)

        # 1. Kiểm tra khu vực an toàn
        if not self.is_safe_area(area_name):
            self.log(f"Từ chối mở sàn: Đang ở vùng nguy hiểm '{area_name}'!")
            return ExchangeResult(
                success=False,
                action_taken="REJECTED_UNSAFE_AREA",
                remaining_chaos=available_chaos,
                remaining_gold=available_gold,
                reason=f"Khu vực '{area_name}' không an toàn để mở sàn ngoại hối.",
                timestamp_ms=now_ms,
            )

        # 2. Kiểm tra nhu cầu restock
        if not self.check_restock_needed(waystone_stock):
            self.log(f"Kho Stash vẫn còn {waystone_stock} Waystone (ngưỡng: {self.config.waystone_restock_threshold}). Bỏ qua.")
            return ExchangeResult(
                success=True,
                action_taken="NO_ACTION_REQUIRED",
                remaining_chaos=available_chaos,
                remaining_gold=available_gold,
                reason=f"Kho Stash còn {waystone_stock} Waystone, chưa chạm mốc bổ sung.",
                timestamp_ms=now_ms,
            )

        # 3. Đánh giá khả năng chi trả
        target_qty = buy_count if (buy_count is not None and buy_count > 0) else self.config.default_buy_count
        feasible, count_to_buy, reason = self.evaluate_restock_feasibility(
            available_chaos=available_chaos,
            available_gold=available_gold,
            target_count=target_qty,
        )

        if not feasible:
            action_code = "REJECTED_LOW_CHAOS" if "Chaos" in reason else "REJECTED_LOW_GOLD"
            self.log(f"Từ chối giao dịch: {reason}")
            return ExchangeResult(
                success=False,
                action_taken=action_code,
                remaining_chaos=available_chaos,
                remaining_gold=available_gold,
                reason=reason,
                timestamp_ms=now_ms,
            )

        # 4. Mở giao diện sàn Faustus qua phím '/'
        if not self.open_currency_exchange():
            return ExchangeResult(
                success=False,
                action_taken="ERROR_CANNOT_OPEN_UI",
                remaining_chaos=available_chaos,
                remaining_gold=available_gold,
                reason="Không thể mở giao diện Faustus Currency Exchange (mất focus hoặc lỗi input).",
                timestamp_ms=now_ms,
            )

        # 5. Thực thi thao tác chọn Chaos Orb -> Mua Waystone T15
        total_chaos_cost = round(count_to_buy * self.config.chaos_per_waystone_t15, 2)
        total_gold_tax = count_to_buy * self.config.gold_tax_per_waystone

        # Click mô phỏng tương tác trên UI Faustus
        self._simulate_or_click_screen(EXCHANGE_CURRENCY_HAVE_POS_2560)
        self._simulate_or_click_screen(EXCHANGE_CURRENCY_WANT_POS_2560)
        self._simulate_or_click_screen(EXCHANGE_CONFIRM_BTN_POS_2560)

        # 6. Đóng giao diện sàn bằng Spacebar
        self.close_currency_exchange()

        # 7. Cập nhật số liệu sau giao dịch
        remaining_chaos = round(available_chaos - total_chaos_cost, 2)
        remaining_gold = available_gold - total_gold_tax
        self.total_restock_operations += 1

        self.log(
            f"Thực thi thành công: Đã mua {count_to_buy} Waystone T15. "
            f"Chi phí: {total_chaos_cost} Chaos, Thuế: {total_gold_tax} Vàng. "
            f"Còn lại: {remaining_chaos} Chaos, {remaining_gold} Vàng."
        )

        return ExchangeResult(
            success=True,
            action_taken="RESTOCKED_WAYSTONES",
            waystones_bought=count_to_buy,
            chaos_spent=total_chaos_cost,
            gold_spent=total_gold_tax,
            remaining_chaos=remaining_chaos,
            remaining_gold=remaining_gold,
            reason=f"Đã mua thành công {count_to_buy} Waystone T15 qua Sàn Faustus.",
            timestamp_ms=now_ms,
        )
