"""Tests for Faustus Currency Exchange Routine & Asset Cascade Optimization.
=============================================================================
Kiểm thử toàn diện:
- Currency Models & Config: Ngưỡng bảo vệ dự trữ, Gold Tax, phân tầng tháp tài sản.
- Portfolio Optimizer:
  * Phase 1: Bán thặng dư crafting/base currency lấy Chaos Orb.
  * Phase 2: Tích lũy Chaos Orb chuyển sang Divine Orb.
  * Phase 3: Tích lũy Divine Orb chuyển sang Mirror of Kalandra.
  * Gold Budget Interlock: Khóa an toàn quỹ vàng và cắt tỉa lệnh khi thiếu vàng.
- Exchange Orchestrator:
  * An toàn khu vực (INV-EXCHANGE-SAFE-AREA).
  * Cooldown & Circuit Breaker.
  * Mở sàn bằng phím '/' (VK_OEM_2) và đóng an toàn bằng Spacebar.
"""

import pytest
from src.assistant_tool.currency_exchange.models import (
    CurrencyItem,
    CurrencyTier,
    ExchangeActionType,
    ExchangeOrder,
    ExchangeOrderStatus,
    ExchangePortfolioConfig,
)
from src.assistant_tool.currency_exchange.portfolio_optimizer import (
    CurrencyPortfolioOptimizer,
    OptimizationResult,
)
from src.assistant_tool.currency_exchange.exchange_orchestrator import (
    CurrencyExchangeOrchestrator,
    ExchangeExecutionReport,
)


class TestCurrencyPortfolioOptimizer:
    def test_reject_when_insufficient_gold(self):
        """Kiểm tra bất biến INV-EXCHANGE-GOLD-TAX: từ chối giao dịch nếu vàng <= 5000."""
        cfg = ExchangePortfolioConfig(min_gold_reserve=5000)
        optimizer = CurrencyPortfolioOptimizer(config=cfg)

        wallet = {"Exalted Orb": 20, "Chaos Orb": 100}
        market_prices = {"Exalted Orb": 12.0, "Divine Orb": 150.0}

        # Vàng chỉ có 4500 <= 5000
        res = optimizer.optimize_portfolio(wallet, market_prices, current_gold=4500)
        assert res.is_affordable is False
        assert len(res.orders) == 0
        assert any("Khóa an toàn Vàng" in note for note in res.summary_notes)

    def test_cascade_phase1_sell_excess_to_chaos(self):
        """Kiểm tra Phase 1: Bán thặng dư crafting currency (giữ lại định mức sinh tồn) lấy Chaos."""
        cfg = ExchangePortfolioConfig(min_gold_reserve=5000)
        # default reserve: Exalted Orb = 5
        optimizer = CurrencyPortfolioOptimizer(config=cfg)

        wallet = {
            "Exalted Orb": 15,    # Thặng dư 15 - 5 = 10 Exalted
            "Chaos Orb": 20,      # Dưới ngưỡng min_chaos_reserve 50
        }
        market_prices = {
            "Exalted Orb": 10.0,  # 10 Exalted * 10 = 100 Chaos
            "Divine Orb": 150.0,
        }

        res = optimizer.optimize_portfolio(wallet, market_prices, current_gold=10000)
        assert res.is_affordable is True
        assert len(res.orders) == 1

        order = res.orders[0]
        assert order.action_type == ExchangeActionType.SELL_TO_CHAOS
        assert order.sell_currency == "Exalted Orb"
        assert order.sell_amount == 10  # Chỉ bán thặng dư
        assert order.expected_buy_amount == 100
        assert order.buy_currency == "Chaos Orb"

    def test_cascade_phase2_convert_chaos_to_divine(self):
        """Kiểm tra Phase 2: Khi tích lũy đủ Chaos -> đổi sang Divine Orb."""
        cfg = ExchangePortfolioConfig(min_gold_reserve=5000, min_chaos_reserve=50)
        optimizer = CurrencyPortfolioOptimizer(config=cfg)

        wallet = {
            "Chaos Orb": 350,   # Có 350 Chaos, giữ lại 50 -> còn 300 Chaos khả dụng
            "Divine Orb": 0,
        }
        market_prices = {
            "Divine Orb": 150.0, # 300 Chaos đổi được đúng 2 Divine!
        }

        res = optimizer.optimize_portfolio(wallet, market_prices, current_gold=10000)
        assert res.is_affordable is True
        assert len(res.orders) == 1

        order = res.orders[0]
        assert order.action_type == ExchangeActionType.CONVERT_CHAOS_TO_DIVINE
        assert order.sell_currency == "Chaos Orb"
        assert order.sell_amount == 300
        assert order.buy_currency == "Divine Orb"
        assert order.expected_buy_amount == 2
        assert res.net_divine_gain == 2

    def test_cascade_phase3_apex_convert_divine_to_mirror(self):
        """Kiểm tra Phase 3: Đỉnh cao tài sản, đổi Divine Orb sang Mirror of Kalandra."""
        cfg = ExchangePortfolioConfig(min_gold_reserve=5000, min_divine_reserve=2)
        optimizer = CurrencyPortfolioOptimizer(config=cfg)

        wallet = {
            "Chaos Orb": 50,
            "Divine Orb": 452,  # Có 452 Divine, giữ lại 2 -> còn 450 Divine khả dụng
            "Mirror of Kalandra": 0,
        }
        # Tỷ giá 1 Divine = 150 Chaos, 1 Mirror = 67500 Chaos -> Mirror = 450 Divine
        market_prices = {
            "Divine Orb": 150.0,
            "Mirror of Kalandra": 67500.0,
        }

        res = optimizer.optimize_portfolio(wallet, market_prices, current_gold=25000)
        assert res.is_affordable is True
        assert len(res.orders) == 1

        order = res.orders[0]
        assert order.action_type == ExchangeActionType.CONVERT_DIVINE_TO_MIRROR
        assert order.sell_currency == "Divine Orb"
        assert order.sell_amount == 450
        assert order.buy_currency == "Mirror of Kalandra"
        assert order.expected_buy_amount == 1
        assert res.net_mirror_gain == 1


class TestCurrencyExchangeOrchestrator:
    def test_unsafe_area_rejected(self):
        """Cấm mở sàn ngoại hối trong map chiến đấu."""
        orchestrator = CurrencyExchangeOrchestrator()
        report = orchestrator.execute_session(
            wallet={"Chaos Orb": 100},
            market_prices_in_chaos={},
            current_gold=10000,
            area_name="Deserted Map (Tier 14)",
            is_simulated=True,
        )
        assert report.status == "REJECTED"
        assert "Vi phạm khu vực an toàn" in report.error

    def test_cooldown_interlock(self):
        """Kiểm tra giãn cách 5 phút giữa 2 phiên đổi tiền."""
        cfg = ExchangePortfolioConfig(cooldown_ms=300000)
        orchestrator = CurrencyExchangeOrchestrator(config=cfg)

        # Giả lập vừa đổi lúc t=100000
        orchestrator.last_exchange_time_ms = 100000

        # Lần gọi tiếp theo lúc t=150000 (< cooldown 300000)
        report = orchestrator.execute_session(
            wallet={"Chaos Orb": 100},
            market_prices_in_chaos={},
            current_gold=10000,
            area_name="Shoreline Hideout",
            is_simulated=True,
            now_ms=150000,
        )
        assert report.status == "REJECTED"
        assert "giãn cách" in report.error

    def test_successful_exchange_session_execution(self):
        """Thực thi thành công một phiên giao dịch ngoại hối tại Hideout."""
        key_presses = []
        def mock_press(vk):
            key_presses.append(vk)

        orchestrator = CurrencyExchangeOrchestrator(press_key_func=mock_press)

        wallet = {
            "Exalted Orb": 25,   # Thặng dư 20 Exalted (20 * 10 = 200 Chaos)
            "Chaos Orb": 0,
        }
        market_prices = {
            "Exalted Orb": 10.0,
            "Divine Orb": 150.0,
        }

        report = orchestrator.execute_session(
            wallet=wallet,
            market_prices_in_chaos=market_prices,
            current_gold=15000,
            area_name="Shoreline Hideout",
            is_simulated=False,
            now_ms=500000,
        )

        assert report.status == "SUCCESS"
        assert report.orders_executed >= 1
        # Phải bấm phím '/' (0xBF) để mở và phím Spacebar (0x20) để đóng
        assert 0xBF in key_presses
        assert 0x20 in key_presses
        assert orchestrator.total_exchanged_sessions == 1
