"""AutoPOE2 - Unit Tests cho Market Price Fetcher & Dynamic Pickit Updater.

Kiểm thử quy đổi tỷ giá Chaos Orb, lọc ngưỡng >= 1.0 Chaos,
và kiểm tra định dạng pickup_filter.json cho C++ Core 120Hz.
Tuân thủ Rule 1, Rule 4, Rule 5.
"""

from __future__ import annotations

import json
import os
import tempfile
import unittest
from unittest.mock import MagicMock, patch

from src.assistant_tool.pickit.market_price_fetcher import MarketPriceFetcher
from src.assistant_tool.pickit.dynamic_pickit_updater import (
    get_valuable_market_items,
    update_pickit_filter_from_market,
    BASELINE_ALWAYS_PICK,
)


class TestMarketPriceFetcher(unittest.TestCase):
    """Kiểm thử bộ thu thập và tính toán tỷ giá thị trường."""

    def test_chaos_calculation_synthetic(self) -> None:
        """Kiểm tra tính toán chaos_value từ dữ liệu giả lập chuẩn."""
        mock_raw_currency = {
            "Items": [
                {"Text": "Mirror of Kalandra", "CurrentPrice": 50000.0},
                {"Text": "Divine Orb", "CurrentPrice": 100.0},
                {"Text": "Chaos Orb", "CurrentPrice": 50.0},
                {"Text": "Orb of Alchemy", "CurrentPrice": 25.0},
                {"Text": "Transmutation Shard", "CurrentPrice": 0.5},
            ]
        }

        with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tmp:
            tmp_cache = tmp.name

        try:
            fetcher = MarketPriceFetcher(cache_path=tmp_cache)
            # Mock _http_get để trả về danh sách mock
            fetcher._http_get = MagicMock(return_value=mock_raw_currency)
            fetcher.get_active_league = MagicMock(return_value="TestLeague")

            data = fetcher.fetch_market_prices(league="TestLeague")
            self.assertEqual(data["league"], "TestLeague")
            self.assertEqual(data["chaos_orb_raw_price"], 50.0)

            items = data["items"]
            # 1. Mirror: 50000 / 50 = 1000 Chaos
            self.assertEqual(items["Mirror of Kalandra"]["chaos_value"], 1000.0)
            # 2. Divine: 100 / 50 = 2.0 Chaos
            self.assertEqual(items["Divine Orb"]["chaos_value"], 2.0)
            # 3. Chaos: 50 / 50 = 1.0 Chaos
            self.assertEqual(items["Chaos Orb"]["chaos_value"], 1.0)
            # 4. Alchemy: 25 / 50 = 0.5 Chaos (< 1.0)
            self.assertEqual(items["Orb of Alchemy"]["chaos_value"], 0.5)
            # 5. Transmutation Shard: 0.5 / 50 = 0.01 Chaos
            self.assertEqual(items["Transmutation Shard"]["chaos_value"], 0.01)
        finally:
            if os.path.exists(tmp_cache):
                os.remove(tmp_cache)


class TestDynamicPickitUpdater(unittest.TestCase):
    """Kiểm thử cập nhật bộ lọc nhặt đồ Pickit theo giá trị >= 1 Chaos."""

    def test_filter_generation_and_threshold(self) -> None:
        """Kiểm tra chỉ các item >= 1 Chaos mới được đưa vào exact_types."""
        mock_market_data = {
            "schema": "autopoE2.market_prices.v1",
            "league": "Runes of Aldur",
            "updated_at": "2026-09-17 03:00:00",
            "chaos_orb_raw_price": 50.0,
            "items": {
                "Mirror of Kalandra": {"name": "Mirror of Kalandra", "chaos_value": 2000.0},
                "Aldur's Legacy": {"name": "Aldur's Legacy", "chaos_value": 500.0},
                "Divine Orb": {"name": "Divine Orb", "chaos_value": 2.5},
                "Chaos Orb": {"name": "Chaos Orb", "chaos_value": 1.0},
                "Lesser Life Flask": {"name": "Lesser Life Flask", "chaos_value": 0.02},
                "Transmutation Shard": {"name": "Transmutation Shard", "chaos_value": 0.01},
            },
        }

        with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tmp_filter:
            out_filter_path = tmp_filter.name

        try:
            with patch("src.assistant_tool.pickit.dynamic_pickit_updater.get_valuable_market_items") as mock_get:
                valuable = {
                    "Mirror of Kalandra": 2000.0,
                    "Aldur's Legacy": 500.0,
                    "Divine Orb": 2.5,
                    "Chaos Orb": 1.0,
                }
                mock_get.return_value = (valuable, mock_market_data)

                res = update_pickit_filter_from_market(
                    min_chaos=1.0, output_paths=[out_filter_path]
                )
                self.assertEqual(res["status"], "success")
                self.assertEqual(res["valuable_items_count"], 4)

                # Đọc lại file JSON đã xuất để kiểm tra tính hợp lệ
                with open(out_filter_path, "r", encoding="utf-8") as f:
                    generated = json.load(f)

                self.assertEqual(generated["schema"], "autopoE2.pickup_filter.v1")
                self.assertEqual(generated["min_chaos_threshold"], 1.0)
                exact = generated["exact_types"]

                # 1. Các item >= 1.0 Chaos BẮT BUỘC phải có
                self.assertIn("Mirror of Kalandra", exact)
                self.assertIn("Aldur's Legacy", exact)
                self.assertIn("Divine Orb", exact)
                self.assertIn("Chaos Orb", exact)

                # 2. Các item baseline sống còn BẮT BUỘC phải có
                for base_item in BASELINE_ALWAYS_PICK:
                    self.assertIn(base_item, exact)

                # 3. Các item rác < 1.0 Chaos TUYỆT ĐỐI KHÔNG ĐƯỢC có
                self.assertNotIn("Lesser Life Flask", exact)
                self.assertNotIn("Transmutation Shard", exact)
        finally:
            if os.path.exists(out_filter_path):
                os.remove(out_filter_path)


class TestMarketPricingPanel(unittest.TestCase):
    """Kiểm thử panel UI Market Pricing và cơ chế đồng bộ."""

    @patch("src.assistant_tool.ui.market_pricing_panel.ctk")
    def test_build_market_pricing_section(self, mock_ctk: MagicMock) -> None:
        """Kiểm tra khởi tạo đầy đủ các widget trên UI."""
        mock_app = MagicMock()
        mock_parent = MagicMock()
        mock_app._create_section_label.return_value = MagicMock()

        from src.assistant_tool.ui.market_pricing_panel import (
            build_market_pricing_section,
        )

        with patch("src.assistant_tool.ui.market_pricing_panel._populate_from_cache_async"):
            build_market_pricing_section(mock_app, mock_parent)

        self.assertTrue(hasattr(mock_app, "lbl_market_league"))
        self.assertTrue(hasattr(mock_app, "lbl_market_rates"))
        self.assertTrue(hasattr(mock_app, "lbl_market_valuable_count"))
        self.assertTrue(hasattr(mock_app, "chk_auto_sync_market"))
        self.assertTrue(hasattr(mock_app, "btn_sync_market_now"))
        self.assertTrue(hasattr(mock_app, "lbl_market_sync_status"))

    def test_run_market_sync_worker(self) -> None:
        """Kiểm tra worker đồng bộ cập nhật chính xác nhãn trạng thái và số item."""
        mock_app = MagicMock()
        mock_app.after = lambda delay, fn: fn()
        mock_app.lbl_market_sync_status = MagicMock()
        mock_app.lbl_market_league = MagicMock()
        mock_app.lbl_market_valuable_count = MagicMock()

        from src.assistant_tool.ui.market_pricing_panel import _run_market_sync_worker

        with patch("src.assistant_tool.ui.market_pricing_panel.update_pickit_filter_from_market") as mock_update:
            mock_update.return_value = {
                "status": "success",
                "valuable_items_count": 42,
                "league": "TestLeague",
            }
            _run_market_sync_worker(mock_app)

            mock_app.lbl_market_league.configure.assert_called_with(text="🌐 Mùa giải: TestLeague")
            mock_app.lbl_market_valuable_count.configure.assert_called_with(
                text="🎯 Số vật phẩm đang nhặt (>= 1.0 Chaos): 42 items"
            )
            self.assertTrue(mock_app.lbl_market_sync_status.configure.called)


if __name__ == "__main__":
    unittest.main()

