"""AutoPOE2 - Unit Tests for Faustus Currency Arbitrage (Doc 68 / Doc 70).
========================================================================
Kiểm thử toàn diện:
- Mô hình hóa đồ thị tỷ giá có hướng (Directed Weighted Graph).
- Thuật toán Dijkstra trên -log(rate) tìm đường chuyển đổi tiền tệ có lợi nhất.
- Phát hiện Arbitrage tam giác có lãi ròng sau khi trừ thuế Vàng (Gold Tax).
- Cơ chế bảo vệ trượt giá an toàn (Slippage Guard <= 3.0%).
- Tối ưu hóa thu mua Waystone T16 với chi phí thấp nhất.
- Thanh lý ngoại tệ thặng dư bảo vệ định mức dự trữ (INV-EXCHANGE-RESERVE-SAFE, INV-EXCHANGE-GOLD-TAX).
"""

import pytest
from src.assistant_tool.economy.faustus_currency_arbitrage import (
    CurrencyEdge,
    ConversionRoute,
    ArbitrageOpportunity,
    LiquidationPlan,
    FaustusCurrencyArbitrage,
)
from src.assistant_tool.currency_exchange.models import ExchangePortfolioConfig


def test_arbitrage_graph_initialization_and_edges():
    """Kiểm tra khởi tạo đồ thị tỷ giá tiền tệ và tính toán log_weight."""
    arbitrage = FaustusCurrencyArbitrage()
    arbitrage.add_rate("Chaos Orb", "Divine Orb", rate=1.0 / 150.0, gold_tax=100, bid_spread=0.01)

    assert "Chaos Orb" in arbitrage.graph
    edge = arbitrage.graph["Chaos Orb"][0]
    assert edge.to_curr == "Divine Orb"
    assert edge.rate == pytest.approx(1.0 / 150.0)
    assert edge.effective_rate == pytest.approx((1.0 / 150.0) * 0.99)
    assert edge.log_weight > 0


def test_dijkstra_best_conversion_path_multi_hop_advantage():
    """
    Kiểm tra thuật toán tìm đường chuyển đổi tốt nhất:
    Trường hợp đường vòng qua Exalted Orb có lợi hơn đổi trực tiếp sang Divine Orb:
    - Trực tiếp: 1 Divine = 150 Chaos (1 Chaos = 0.00666 Divine)
    - Gián tiếp: 1 Chaos = 0.1 Exalt; 1 Exalt = 0.075 Divine -> 1 Chaos = 0.0075 Divine (+12.5% lợi nhuận)
    """
    arbitrage = FaustusCurrencyArbitrage(max_slippage_pct=5.0)

    # Đổi trực tiếp
    arbitrage.add_rate("Chaos Orb", "Divine Orb", rate=1.0 / 150.0, bid_spread=0.01)

    # Đổi gián tiếp qua Exalted Orb
    arbitrage.add_rate("Chaos Orb", "Exalted Orb", rate=0.10, bid_spread=0.005)
    arbitrage.add_rate("Exalted Orb", "Divine Orb", rate=0.075, bid_spread=0.005)

    route = arbitrage.find_best_conversion_path("Chaos Orb", "Divine Orb", amount_in=100.0)
    assert route is not None
    assert len(route.hops) == 2
    assert route.hops[0].from_curr == "Chaos Orb"
    assert route.hops[0].to_curr == "Exalted Orb"
    assert route.hops[1].from_curr == "Exalted Orb"
    assert route.hops[1].to_curr == "Divine Orb"
    assert route.path_str == "Chaos Orb -> Exalted Orb -> Divine Orb"
    assert route.rate_advantage_pct > 0  # Có lợi thế hơn đường trực tiếp
    assert route.final_amount > 100.0 * (1.0 / 150.0) * 0.99


def test_slippage_guard_rejects_excessive_hops():
    """INV-EXCHANGE-SLIPPAGE-GUARD: Cấm các tuyến đường có ước tính trượt giá > max_slippage_pct (<= 3.0%)."""
    arbitrage = FaustusCurrencyArbitrage(max_slippage_pct=3.0)

    # Tạo tuyến đường 4 hops (ước tính trượt giá 4% > 3%)
    arbitrage.add_rate("A", "B", rate=1.2)
    arbitrage.add_rate("B", "C", rate=1.2)
    arbitrage.add_rate("C", "D", rate=1.2)
    arbitrage.add_rate("D", "E", rate=1.2)

    route = arbitrage.find_best_conversion_path("A", "E", amount_in=10.0)
    assert route is None, "Phải từ chối tuyến đường vượt ngưỡng trượt giá 3.0%!"


def test_detect_triangular_arbitrage_profitable():
    """Kiểm tra phát hiện cơ hội Arbitrage tam giác có lãi ròng sau thuế Vàng."""
    arbitrage = FaustusCurrencyArbitrage(
        chaos_per_gold_rate=0.0001,  # 10,000 Gold = 1 Chaos
        min_gold_reserve=3000,
    )

    # Giả lập thị trường có chênh lệch tỷ giá tam giác (Chaos -> Exalt -> Div -> Chaos)
    # 100 Chaos -> 12 Exalt -> 1.05 Divine -> 160 Chaos (Lãi gộp 60 Chaos)
    arbitrage.add_rate("Chaos Orb", "Exalted Orb", rate=0.12, gold_tax=5, bid_spread=0.005)
    arbitrage.add_rate("Exalted Orb", "Divine Orb", rate=0.088, gold_tax=10, bid_spread=0.005)
    arbitrage.add_rate("Divine Orb", "Chaos Orb", rate=155.0, gold_tax=20, bid_spread=0.005)

    opps = arbitrage.detect_triangular_arbitrage(base_currency="Chaos Orb", test_amount=100.0, current_gold=20000)
    assert len(opps) > 0
    best_opp = opps[0]
    assert best_opp.cycle_path == ["Chaos Orb", "Exalted Orb", "Divine Orb", "Chaos Orb"]
    assert best_opp.gross_profit_pct > 10.0
    assert best_opp.net_profit_chaos > 5.0
    assert best_opp.is_executable is True


def test_detect_triangular_arbitrage_rejects_when_gold_depleted():
    """INV-EXCHANGE-GOLD-TAX: Từ chối Arbitrage nếu số dư Vàng sau thuế < min_gold_reserve."""
    arbitrage = FaustusCurrencyArbitrage(min_gold_reserve=10000)

    arbitrage.add_rate("Chaos Orb", "Exalted Orb", rate=0.15, gold_tax=2000, bid_spread=0.005)
    arbitrage.add_rate("Exalted Orb", "Divine Orb", rate=0.10, gold_tax=3000, bid_spread=0.005)
    arbitrage.add_rate("Divine Orb", "Chaos Orb", rate=150.0, gold_tax=4000, bid_spread=0.005)

    # Thuế tổng cộng 9,000 Gold. Quỹ ban đầu 12,000 -> còn 3,000 (< 10,000 min_reserve)
    opps = arbitrage.detect_triangular_arbitrage(base_currency="Chaos Orb", test_amount=1.0, current_gold=12000)
    assert len(opps) > 0
    assert opps[0].is_executable is False
    assert "thap hon nguong toi thieu" in opps[0].reason


def test_plan_waystone_purchase_cheapest_route():
    """Kiểm tra tìm tuyến mua Waystone T16 với chi phí thấp nhất từ ví tiền tệ."""
    arbitrage = FaustusCurrencyArbitrage()

    # Tỷ giá bán Waystone T16:
    # 1 Chaos Orb -> 0.0833 Waystone (12 Chaos = 1 Waystone)
    # 1 Divine Orb -> 15 Waystone (1 Divine = 15 Waystone ~ 9.67 Chaos/Waystone, rẻ hơn!)
    arbitrage.add_rate("Chaos Orb", "Waystone (Tier 16)", rate=1.0 / 12.0)
    arbitrage.add_rate("Divine Orb", "Waystone (Tier 16)", rate=15.0)

    # Ví có 100 Chaos (dự trữ 50 -> dư 50) và 3 Divine (dự trữ 2 -> dư 1 Divine)
    wallet = {
        "Chaos Orb": 100,
        "Divine Orb": 3,
    }

    route = arbitrage.plan_waystone_purchase(
        target_tier=16,
        count=5,
        available_wallet=wallet,
        current_gold=15000,
    )
    assert route is not None
    assert route.source_curr == "Divine Orb"
    assert route.final_amount >= 5


def test_plan_surplus_liquidation_preserves_reserves():
    """Kiểm tra thanh lý ngoại tệ phụ sang Divine Orb bảo toàn định mức dự trữ an toàn."""
    cfg = ExchangePortfolioConfig()
    cfg.default_reserves["Orb of Alteration"] = 40
    cfg.default_reserves["Orb of Alchemy"] = 20
    cfg.default_reserves["Chaos Orb"] = 50

    arbitrage = FaustusCurrencyArbitrage(config=cfg, min_gold_reserve=3000)
    arbitrage.add_rate("Orb of Alteration", "Chaos Orb", rate=0.20, gold_tax=5)
    arbitrage.add_rate("Orb of Alchemy", "Chaos Orb", rate=0.50, gold_tax=10)
    arbitrage.add_rate("Chaos Orb", "Divine Orb", rate=1.0 / 145.0, gold_tax=250)

    # Ví có:
    # Alteration: 240 (dự trữ 40 -> bán 200 -> được 40 Chaos)
    # Alchemy: 120 (dự trữ 20 -> bán 100 -> được 50 Chaos)
    # Chaos: 205 (dự trữ 50 -> dư 155 Chaos)
    # Tổng Chaos khả dụng để mua Divine: 40 + 50 + 155 = 245 Chaos (~ 1 Divine)
    wallet = {
        "Orb of Alteration": 240,
        "Orb of Alchemy": 120,
        "Chaos Orb": 205,
    }

    plan = arbitrage.plan_surplus_liquidation(wallet, current_gold=15000)
    assert plan.total_orders >= 2
    assert "Orb of Alteration" in plan.source_currencies
    assert "Orb of Alchemy" in plan.source_currencies
    assert plan.projected_divine_earned >= 1
    assert plan.remaining_gold_balance >= 3000

    # Kiểm tra các lệnh được sinh ra
    alt_order = next((o for o in plan.orders if o.sell_currency == "Orb of Alteration"), None)
    assert alt_order is not None
    assert alt_order.sell_amount == 200  # 240 - 40 reserve
