"""AutoPOE2 - Currency Portfolio Optimizer (Doc 43 / Doc 68 / Doc 69).
=====================================================================
Thuật toán tối ưu hóa danh mục tiền tệ theo mô hình Thác Lũy Tiến (Currency Cascade Waterfall):
1. Tầng 1: Thu gom toàn bộ thặng dư currency cấp thấp & crafting (Tier 4 / Tier 3) đổi sang Chaos Orb.
2. Tầng 2: Khi Chaos Orb vượt ngưỡng dự trữ an toàn (min_chaos_reserve) và đủ mua 1 Divine Orb -> Đổi sang Divine.
3. Tầng 3: Khi Divine Orb tích lũy vượt ngưỡng giá Mirror of Kalandra -> Đổi sang Mirror of Kalandra.
4. Kiểm soát ngân sách Vàng (Gold Budget Interlock): Đảm bảo tổng phí giao dịch không xâm phạm quỹ vàng sinh tồn (min_gold_reserve).

Tuân thủ nghiêm ngặt:
- Rule 1: Cold Path Tier 2 (Python 3.11).
- Rule 4: Module hóa, trần file < 500 dòng.
- Bất biến: INV-EXCHANGE-GOLD-TAX & INV-EXCHANGE-RESERVE-SAFE.
"""

from __future__ import annotations

import math
import uuid
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Set, Tuple

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


@dataclass
class OptimizationResult:
    """Kết quả tối ưu hóa danh mục tiền tệ."""
    orders: List[ExchangeOrder]
    total_gold_tax: int
    net_chaos_gain: float
    net_divine_gain: int
    net_mirror_gain: int
    is_affordable: bool
    summary_notes: List[str] = field(default_factory=list)


class CurrencyPortfolioOptimizer:
    """Bộ tối ưu danh mục tiền tệ tự hành."""

    def __init__(self, config: Optional[ExchangePortfolioConfig] = None):
        self.config = config or ExchangePortfolioConfig()

    def optimize_portfolio(
        self,
        wallet: Dict[str, int],
        market_prices_in_chaos: Dict[str, float],
        current_gold: int,
    ) -> OptimizationResult:
        """
        Phân tích số dư ví, đối soát giá thị trường và sinh danh sách lệnh giao dịch tối ưu.
        """
        notes: List[str] = []
        available_gold = current_gold - self.config.min_gold_reserve

        # 1. Khóa an toàn Vàng (INV-EXCHANGE-GOLD-TAX)
        if available_gold <= 0:
            notes.append(
                f"Khóa an toàn Vàng: Quỹ vàng hiện tại ({current_gold}) <= "
                f"ngưỡng bảo vệ ({self.config.min_gold_reserve}). Từ chối giao dịch sàn."
            )
            return OptimizationResult(
                orders=[],
                total_gold_tax=0,
                net_chaos_gain=0.0,
                net_divine_gain=0,
                net_mirror_gain=0,
                is_affordable=False,
                summary_notes=notes,
            )

        candidate_orders: List[ExchangeOrder] = []
        projected_chaos = float(wallet.get("Chaos Orb", 0))
        projected_divine = int(wallet.get("Divine Orb", 0))
        projected_mirror = int(wallet.get("Mirror of Kalandra", 0))

        # Tỷ giá thị trường quy chuẩn
        divine_rate_in_chaos = market_prices_in_chaos.get("Divine Orb", 150.0)
        mirror_rate_in_divine = 450.0
        if "Mirror of Kalandra" in market_prices_in_chaos and divine_rate_in_chaos > 0:
            mirror_rate_in_divine = market_prices_in_chaos["Mirror of Kalandra"] / divine_rate_in_chaos

        # =========================================================================
        # PHASE 1: Thu gom currency phụ / crafting (Tier 4 & Tier 3 thặng dư) sang Chaos
        # =========================================================================
        for name, qty in wallet.items():
            if name in ("Chaos Orb", "Divine Orb", "Mirror of Kalandra"):
                continue

            min_res = self.config.default_reserves.get(name, 0)
            surplus = qty - min_res
            if surplus <= 0:
                continue

            unit_chaos_val = market_prices_in_chaos.get(name, 0.0)
            if unit_chaos_val <= 0.0:
                continue

            total_val_chaos = surplus * unit_chaos_val
            # Chỉ đổi nếu tổng giá trị lô hàng >= 1.0 Chaos
            if total_val_chaos >= 1.0:
                expected_chaos = int(math.floor(total_val_chaos))
                if expected_chaos >= 1:
                    gold_tax = surplus * 25  # Phí vàng ước tính 25 gold/unit cho tier 3/4
                    order = ExchangeOrder(
                        order_id=f"ORD_SELL_{name.replace(' ', '_').upper()}_{uuid.uuid4().hex[:6]}",
                        action_type=ExchangeActionType.SELL_TO_CHAOS,
                        sell_currency=name,
                        sell_amount=surplus,
                        buy_currency="Chaos Orb",
                        expected_buy_amount=expected_chaos,
                        market_rate=round(unit_chaos_val, 4),
                        estimated_gold_tax=gold_tax,
                        status=ExchangeOrderStatus.PENDING,
                        reason=f"Thu gom thặng dư {surplus} {name} (dự trữ an toàn: {min_res}) sang {expected_chaos} Chaos.",
                    )
                    candidate_orders.append(order)
                    projected_chaos += expected_chaos

        # =========================================================================
        # PHASE 2: Tích lũy Chaos chuyển sang Divine Orb
        # =========================================================================
        tradable_chaos = projected_chaos - self.config.min_chaos_reserve
        if tradable_chaos >= divine_rate_in_chaos:
            divines_to_buy = int(tradable_chaos // divine_rate_in_chaos)
            chaos_to_spend = int(divines_to_buy * divine_rate_in_chaos)
            divine_gold_tax = divines_to_buy * 350  # 350 gold/divine

            order_divine = ExchangeOrder(
                order_id=f"ORD_CONV_DIVINE_{uuid.uuid4().hex[:6]}",
                action_type=ExchangeActionType.CONVERT_CHAOS_TO_DIVINE,
                sell_currency="Chaos Orb",
                sell_amount=chaos_to_spend,
                buy_currency="Divine Orb",
                expected_buy_amount=divines_to_buy,
                market_rate=round(1.0 / divine_rate_in_chaos, 6),
                estimated_gold_tax=divine_gold_tax,
                status=ExchangeOrderStatus.PENDING,
                reason=f"Tích lũy {chaos_to_spend} Chaos (giữ lại {self.config.min_chaos_reserve} Chaos cơ sở) đổi lấy {divines_to_buy} Divine Orb.",
            )
            candidate_orders.append(order_divine)
            projected_chaos -= chaos_to_spend
            projected_divine += divines_to_buy

        # =========================================================================
        # PHASE 3: Đỉnh cao tích lũy Divine sang Mirror of Kalandra
        # =========================================================================
        tradable_divine = projected_divine - self.config.min_divine_reserve
        if tradable_divine >= mirror_rate_in_divine:
            mirrors_to_buy = int(tradable_divine // mirror_rate_in_divine)
            divine_to_spend = int(mirrors_to_buy * mirror_rate_in_divine)
            mirror_gold_tax = mirrors_to_buy * 5000  # 5,000 gold/mirror

            order_mirror = ExchangeOrder(
                order_id=f"ORD_CONV_MIRROR_{uuid.uuid4().hex[:6]}",
                action_type=ExchangeActionType.CONVERT_DIVINE_TO_MIRROR,
                sell_currency="Divine Orb",
                sell_amount=divine_to_spend,
                buy_currency="Mirror of Kalandra",
                expected_buy_amount=mirrors_to_buy,
                market_rate=round(1.0 / mirror_rate_in_divine, 6),
                estimated_gold_tax=mirror_gold_tax,
                status=ExchangeOrderStatus.PENDING,
                reason=f"Đỉnh cao tài sản: Tích lũy {divine_to_spend} Divine Orb đổi lấy {mirrors_to_buy} Mirror of Kalandra!",
            )
            candidate_orders.append(order_mirror)
            projected_divine -= divine_to_spend
            projected_mirror += mirrors_to_buy

        # =========================================================================
        # PHASE 4: Điều chỉnh ngân sách Vàng (Gold Budget Interlock)
        # =========================================================================
        total_tax = sum(ord.estimated_gold_tax for ord in candidate_orders)

        # Nếu thiếu vàng trả phí, cắt giảm bớt các lệnh bán phụ có giá trị thấp nhất
        final_orders: List[ExchangeOrder] = []
        if total_tax > available_gold:
            notes.append(f"Cảnh báo: Tổng phí vàng ({total_tax}) > ngân sách khả dụng ({available_gold}). Điều chỉnh danh mục.")
            # Ưu tiên giữ lại lệnh đổi Divine và Mirror
            high_priority = [o for o in candidate_orders if o.action_type != ExchangeActionType.SELL_TO_CHAOS]
            low_priority = [o for o in candidate_orders if o.action_type == ExchangeActionType.SELL_TO_CHAOS]
            # Sắp xếp các lệnh bán phụ theo tỷ lệ giá trị/thuế
            low_priority.sort(key=lambda o: o.expected_buy_amount / max(1, o.estimated_gold_tax), reverse=True)

            acc_tax = 0
            for o in high_priority:
                if acc_tax + o.estimated_gold_tax <= available_gold:
                    final_orders.append(o)
                    acc_tax += o.estimated_gold_tax

            for o in low_priority:
                if acc_tax + o.estimated_gold_tax <= available_gold:
                    final_orders.append(o)
                    acc_tax += o.estimated_gold_tax

            total_tax = acc_tax
        else:
            final_orders = candidate_orders

        net_chaos = projected_chaos - wallet.get("Chaos Orb", 0)
        net_divine = projected_divine - wallet.get("Divine Orb", 0)
        net_mirror = projected_mirror - wallet.get("Mirror of Kalandra", 0)

        notes.append(
            f"Kế hoạch giao dịch: {len(final_orders)} lệnh | Phí vàng: {total_tax} Gold | "
            f"Tài sản tăng ròng: {net_chaos:+.1f} Chaos, {net_divine:+d} Divine, {net_mirror:+d} Mirror."
        )

        return OptimizationResult(
            orders=final_orders,
            total_gold_tax=total_tax,
            net_chaos_gain=round(net_chaos, 2),
            net_divine_gain=net_divine,
            net_mirror_gain=net_mirror,
            is_affordable=True,
            summary_notes=notes,
        )
