"""AutoPOE2 - Faustus Order Queue Manager & Auto-Restock Cycle (Doc 70 Mục 5.5 / Chu Kỳ 8).
======================================================================================
Bộ quản trị hàng đợi 10 slots sàn Faustus Currency Exchange (phím '/'):
1. Quản lý 10 vị trí đặt lệnh (Pending Order Slots 0..9) trên sàn giao dịch.
2. Tự động nhận tiền tệ đã khớp (Claim Completed Trades) giải phóng slot.
3. Tự động đặt lệnh mua Waystone cấp cao (Tier 15-16) bằng Chaos Orb khi số lượng
   khả dụng trong hòm đồ và túi đồ <= 3 viên (Bất biến INV-WAYSTONE-RESTOCK-MIN).

Tuân thủ nghiêm ngặt:
- Rule 1: Cold Path Tier 2 (Python 3.11).
- Rule 4: Module hóa độc lập, trần file < 500 dòng.
- Rule 5: Báo cáo gắn nhãn [MÔ PHỎNG THUẬT TOÁN HEADLESS - KHÔNG PHẢI LIVE GAME].
- Rule 7: Phím '/' mở sàn Faustus, Spacebar đóng sàn.
- Bất biến: INV-EXCHANGE-GOLD-TAX, INV-EXCHANGE-RESERVE-SAFE, INV-WAYSTONE-RESTOCK-MIN.
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Tuple

from src.assistant_tool.currency_exchange.models import (
    CurrencyTier,
    ExchangeActionType,
    ExchangeOrder,
    ExchangeOrderStatus,
    ExchangePortfolioConfig,
)


@dataclass
class FaustusOrderSlot:
    """Mô tả một slot đặt lệnh trên sàn Faustus (Tổng cộng 10 slots: 0 -> 9)."""
    slot_id: int
    order: Optional[ExchangeOrder] = None
    filled_amount: int = 0
    is_ready_to_claim: bool = False
    submitted_at: Optional[str] = None

    @property
    def is_empty(self) -> bool:
        return self.order is None


@dataclass
class ClaimTradeResult:
    """Kết quả nhận tiền tệ đã khớp từ một slot sàn Faustus."""
    slot_id: int
    order_id: str
    claimed_currency: str
    claimed_amount: int
    freed_slot_id: int
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())


class FaustusOrderManager:
    """Bộ quản trị hàng đợi 10 slots và bổ sung Waystone tự động."""

    MAX_SLOTS: int = 10
    WAYSTONE_RESTOCK_MIN_THRESHOLD: int = 3  # INV-WAYSTONE-RESTOCK-MIN

    def __init__(
        self,
        config: Optional[ExchangePortfolioConfig] = None,
        waystone_price_in_chaos: float = 10.0,
    ):
        self.config = config or ExchangePortfolioConfig()
        self.waystone_price_in_chaos = waystone_price_in_chaos
        self.slots: List[FaustusOrderSlot] = [
            FaustusOrderSlot(slot_id=i) for i in range(self.MAX_SLOTS)
        ]
        self.claim_history: List[ClaimTradeResult] = []

    @property
    def occupied_slots_count(self) -> int:
        """Số lượng slot đang chứa lệnh giao dịch."""
        return sum(1 for s in self.slots if not s.is_empty)

    @property
    def available_slots_count(self) -> int:
        """Số lượng slot trống sẵn sàng nhận lệnh mới."""
        return self.MAX_SLOTS - self.occupied_slots_count

    def get_first_empty_slot(self) -> Optional[int]:
        """Tìm chỉ số slot trống đầu tiên (0..9)."""
        for s in self.slots:
            if s.is_empty:
                return s.slot_id
        return None

    def submit_order(self, order: ExchangeOrder) -> Tuple[bool, str, Optional[int]]:
        """
        Nộp một lệnh giao dịch mới vào slot trống của Faustus.
        Từ chối nếu cả 10 slots đều đã bị chiếm dụng.
        """
        empty_slot_id = self.get_first_empty_slot()
        if empty_slot_id is None:
            order.status = ExchangeOrderStatus.CANCELLED
            order.reason = f"San Faustus da day 10/10 slots. Khong the nop lenh {order.order_id}."
            return False, order.reason, None

        order.status = ExchangeOrderStatus.SUBMITTED
        self.slots[empty_slot_id] = FaustusOrderSlot(
            slot_id=empty_slot_id,
            order=order,
            filled_amount=0,
            is_ready_to_claim=False,
            submitted_at=datetime.now().isoformat(),
        )
        return True, f"Lenh {order.order_id} da nop thanh cong vao slot {empty_slot_id}.", empty_slot_id

    def simulate_order_fill(self, slot_id: int, filled_amount: Optional[int] = None) -> bool:
        """
        Mô phỏng sự kiện lệnh được khớp (Fill Order) phục vụ Headless Runner và Tests.
        """
        if slot_id < 0 or slot_id >= self.MAX_SLOTS:
            return False

        slot = self.slots[slot_id]
        if slot.is_empty or not slot.order:
            return False

        fill = filled_amount if filled_amount is not None else slot.order.expected_buy_amount
        slot.filled_amount = fill
        if slot.filled_amount >= slot.order.expected_buy_amount:
            slot.order.status = ExchangeOrderStatus.COMPLETED
            slot.is_ready_to_claim = True
        return True

    def claim_all_completed_trades(self) -> List[ClaimTradeResult]:
        """
        Quét toàn bộ các slots đã khớp (COMPLETED / READY_TO_CLAIM),
        tự động nhận tiền tệ và giải phóng slot.
        """
        claimed_results: List[ClaimTradeResult] = []
        for slot in self.slots:
            if not slot.is_empty and slot.is_ready_to_claim and slot.order:
                claimed = ClaimTradeResult(
                    slot_id=slot.slot_id,
                    order_id=slot.order.order_id,
                    claimed_currency=slot.order.buy_currency,
                    claimed_amount=slot.filled_amount,
                    freed_slot_id=slot.slot_id,
                )
                claimed_results.append(claimed)
                self.claim_history.append(claimed)
                # Giải phóng slot về trạng thái trống
                self.slots[slot.slot_id] = FaustusOrderSlot(slot_id=slot.slot_id)

        return claimed_results

    def cancel_expired_orders(
        self,
        max_ttl_sec: float = 180.0,
        now: Optional[datetime] = None,
    ) -> List[Tuple[int, str, str]]:
        """
        Quét và tự động hủy các lệnh treo quá thời gian cho phép (Time-To-Live TTL = 180s ~ 1 Map).
        Thu hồi vốn và giải phóng slot trên sàn Faustus để tránh kẹt tài sản.
        Trả về danh sách: [(slot_id, order_id, reason), ...]
        """
        cancelled_list: List[Tuple[int, str, str]] = []
        current_time = now or datetime.now()
        for slot in self.slots:
            if not slot.is_empty and slot.order and not slot.is_ready_to_claim:
                if slot.submitted_at:
                    try:
                        sub_dt = datetime.fromisoformat(slot.submitted_at)
                        elapsed = (current_time - sub_dt).total_seconds()
                    except Exception:
                        elapsed = 0.0

                    if elapsed >= max_ttl_sec:
                        oid = slot.order.order_id
                        slot.order.status = ExchangeOrderStatus.CANCELLED
                        reason = f"Lenh {oid} het han TTL ({elapsed:.1f}s >= {max_ttl_sec}s). Tu dong huy de thu hoi von."
                        slot.order.reason = reason
                        cancelled_list.append((slot.slot_id, oid, reason))
                        # Giải phóng slot về trạng thái trống
                        self.slots[slot.slot_id] = FaustusOrderSlot(slot_id=slot.slot_id)

        return cancelled_list

    def check_and_generate_waystone_restock(
        self,
        total_waystones_owned: int,
        available_chaos: int,
        current_gold: int,
        target_tier: int = 16,
        buy_count: int = 5,
    ) -> Optional[ExchangeOrder]:
        """
        Kiểm tra bất biến INV-WAYSTONE-RESTOCK-MIN:
        Khi tổng Waystone sở hữu <= 3 viên:
        - Tự động sinh lệnh mua Waystone cấp cao (Tier 15-16) bằng Chaos Orb.
        - Bảo đảm quỹ Vàng duy trì >= 5,000 Gold (INV-EXCHANGE-GOLD-TAX).
        - Bảo đảm Chaos Orb còn lại >= min_chaos_reserve (50 Chaos).
        - Kiểm tra còn slot trống trên sàn.
        """
        if total_waystones_owned > self.WAYSTONE_RESTOCK_MIN_THRESHOLD:
            return None  # Đủ Waystones, không cần restock

        if self.available_slots_count <= 0:
            return None  # Sàn hết slot

        total_cost_chaos = int(buy_count * self.waystone_price_in_chaos)
        surplus_chaos = available_chaos - self.config.min_chaos_reserve
        if surplus_chaos < total_cost_chaos:
            return None  # Không đủ Chaos Orb dự trữ

        estimated_tax = buy_count * 50  # 50 Gold mỗi viên Waystone Tier cao
        if (current_gold - estimated_tax) < self.config.min_gold_reserve:
            return None  # Không đủ Vàng bảo vệ

        waystone_name = f"Waystone (Tier {target_tier})"
        order = ExchangeOrder(
            order_id=f"order_restock_ws_{uuid.uuid4().hex[:6]}",
            action_type=ExchangeActionType.SELL_TO_CHAOS,  # Đổi Chaos lấy Waystone
            sell_currency="Chaos Orb",
            sell_amount=total_cost_chaos,
            buy_currency=waystone_name,
            expected_buy_amount=buy_count,
            market_rate=1.0 / self.waystone_price_in_chaos,
            estimated_gold_tax=estimated_tax,
            status=ExchangeOrderStatus.PENDING,
            reason=f"INV-WAYSTONE-RESTOCK-MIN: So luong Waystone con {total_waystones_owned} <= {self.WAYSTONE_RESTOCK_MIN_THRESHOLD}",
        )
        return order

    def format_ascii_order_board(self) -> str:
        """Định dạng bảng theo dõi 10 slots của Faustus chuẩn Rule 5 (ASCII-safe)."""
        lines = [
            "=" * 78,
            " [MO PHONG THUAT TOAN HEADLESS - KHONG PHAI LIVE GAME]",
            " BANG QUAN TRI 10 SLOTS SAN FAUSTUS CURRENCY EXCHANGE (FAUSTUS ORDER BOARD)",
            "=" * 78,
            f" Tong So Slots             : {self.MAX_SLOTS}",
            f" Slots Dang Dung (Occupied): {self.occupied_slots_count} / {self.MAX_SLOTS}",
            f" Slots Con Trong (Available): {self.available_slots_count} / {self.MAX_SLOTS}",
            "-" * 78,
            " TRANG THAI CHI TIET TUNG SLOT:",
        ]

        for s in self.slots:
            if s.is_empty:
                lines.append(f"   Slot {s.slot_id:>2}: [TRONG / SAN SANG NHAN LENH]")
            else:
                ord_info = s.order
                status_str = "READY TO CLAIM" if s.is_ready_to_claim else (ord_info.status.value if ord_info else "UNKNOWN")
                sell_info = f"Ban {ord_info.sell_amount} {ord_info.sell_currency}" if ord_info else ""
                buy_info = f"Mua {ord_info.expected_buy_amount} {ord_info.buy_currency}" if ord_info else ""
                lines.append(
                    f"   Slot {s.slot_id:>2}: [{status_str:<14}] {sell_info:<25} -> {buy_info:<25} "
                    f"(Filled: {s.filled_amount}/{ord_info.expected_buy_amount if ord_info else 0})"
                )

        lines.append("=" * 78)
        return "\n".join(lines)
