"""AutoPOE2 - Market Price Fetcher (POE2 Scout API Integration).

Truy vấn giá cả thị trường thời gian thực từ POE2 Scout API (api.poe2scout.com),
tính toán giá trị quy đổi sang Chaos Orb và lưu cache cục bộ.
Tuân thủ Rule 1 (Tier 2 Cold Path), Rule 4 (Kiến Trúc Module Hóa), Rule 5 (Dữ Liệu Thật).
"""

from __future__ import annotations

import json
import os
import time
import urllib.parse
import urllib.request
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple

API_BASE_URL = "https://api.poe2scout.com"
DEFAULT_USER_AGENT = "AutoPOE2-MarketSync/1.0 (contact: admin@autopoe2.local)"
DEFAULT_CACHE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "data", "market_prices.json"))

# Danh mục tiền tệ & vật phẩm quan trọng cần theo dõi giá
MONITORED_CATEGORIES = [
    "currency",
    "runes",
    "essences",
    "ultimatum",
    "ritual",
    "delirium",
    "uncutgems",
    "fragments",
    "vaultkeys",
    "breach",
    "abyss",
    "incursion",
]


class MarketPriceFetcher:
    """Bộ thu thập và phân tích giá thị trường POE2 thời gian thực."""

    def __init__(
        self,
        base_url: str = API_BASE_URL,
        user_agent: str = DEFAULT_USER_AGENT,
        cache_path: str = DEFAULT_CACHE_PATH,
    ):
        self.base_url = base_url.rstrip("/")
        self.user_agent = user_agent
        self.cache_path = cache_path

    def _http_get(self, endpoint: str, timeout: float = 8.0) -> Any:
        """Gửi GET request tới API và trả về JSON đã phân tích."""
        url = f"{self.base_url}{endpoint}"
        req = urllib.request.Request(url, headers={"User-Agent": self.user_agent})
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            if resp.status != 200:
                raise RuntimeError(f"HTTP Error {resp.status} on {url}")
            return json.loads(resp.read().decode("utf-8"))

    def get_active_league(self) -> str:
        """Lấy tên League đang diễn ra (IsCurrent: true) hoặc fallback sang Standard."""
        try:
            leagues = self._http_get("/poe2/Leagues")
            for league in leagues:
                if league.get("IsCurrent", False):
                    return league.get("Value", "Runes of Aldur")
            return "Standard"
        except Exception:
            return "Standard"

    def fetch_market_prices(
        self, league: Optional[str] = None, max_retries: int = 2
    ) -> Dict[str, Any]:
        """Truy vấn giá thị trường cho toàn bộ danh mục và tính giá trị Chaos.

        Returns:
            Dict chứa metadata, giá mốc Chaos, và từ điển các item kèm chaos_value.
        """
        active_league = league or self.get_active_league()
        encoded_league = urllib.parse.quote(active_league)

        raw_items: List[Dict[str, Any]] = []

        for cat in MONITORED_CATEGORIES:
            endpoint = f"/poe2/Leagues/{encoded_league}/Currencies/ByCategory?Category={cat}"
            for attempt in range(max_retries):
                try:
                    data = self._http_get(endpoint, timeout=6.0)
                    items = data.get("Items", []) if isinstance(data, dict) else []
                    for item in items:
                        item["_category"] = cat
                    raw_items.extend(items)
                    break
                except Exception:
                    if attempt == max_retries - 1:
                        pass
                    time.sleep(0.3)

        if not raw_items:
            raise RuntimeError(f"Không thể tải bất kỳ dữ liệu giá nào cho League '{active_league}'.")

        # 1. Xác định giá mốc của Chaos Orb
        chaos_orb_price: float = 50.0  # Fallback mốc mặc định nếu không thấy
        for item in raw_items:
            text = item.get("Text", "").strip()
            if text.lower() == "chaos orb":
                p = item.get("CurrentPrice")
                if p and p > 0:
                    chaos_orb_price = float(p)
                    break

        # 2. Quy đổi toàn bộ item sang đơn vị Chaos Orb
        parsed_items: Dict[str, Dict[str, Any]] = {}
        for item in raw_items:
            name = item.get("Text", "").strip()
            if not name:
                continue

            current_price = item.get("CurrentPrice")
            if current_price is None:
                # Thử lấy giá gần nhất từ PriceLogs
                logs = item.get("PriceLogs", [])
                if logs and isinstance(logs, list):
                    current_price = logs[-1].get("Price")

            if current_price is None or current_price <= 0:
                continue

            price_float = float(current_price)
            chaos_val = price_float / chaos_orb_price

            parsed_items[name] = {
                "name": name,
                "category": item.get("_category", "unknown"),
                "raw_price": round(price_float, 2),
                "chaos_value": round(chaos_val, 2),
                "icon_url": item.get("IconUrl", ""),
            }

        # Đảm bảo Chaos Orb luôn có giá trị đúng 1.0 Chaos
        parsed_items["Chaos Orb"] = {
            "name": "Chaos Orb",
            "category": "currency",
            "raw_price": round(chaos_orb_price, 2),
            "chaos_value": 1.0,
            "icon_url": "",
        }

        result = {
            "schema": "autopoE2.market_prices.v1",
            "league": active_league,
            "updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "chaos_orb_raw_price": round(chaos_orb_price, 2),
            "total_items": len(parsed_items),
            "items": parsed_items,
        }

        # Lưu cache cục bộ
        self.save_cache(result)
        return result

    def save_cache(self, data: Dict[str, Any]) -> None:
        """Lưu dữ liệu giá vào tệp cache JSON."""
        os.makedirs(os.path.dirname(self.cache_path), exist_ok=True)
        with open(self.cache_path, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2, ensure_ascii=False)

    def load_cache(self, max_age_seconds: Optional[float] = None) -> Optional[Dict[str, Any]]:
        """Nạp cache cục bộ nếu tệp tồn tại và chưa hết hạn."""
        if not os.path.exists(self.cache_path):
            return None

        if max_age_seconds is not None:
            mtime = os.path.getmtime(self.cache_path)
            if time.time() - mtime > max_age_seconds:
                return None

        try:
            with open(self.cache_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return None
