"""AutoPOE2 - Atlas Passive Tree Planner & Max Profit Blueprint (Doc 65 / Doc 70).
================================================================================
Thiết kế bộ hoạch định phân bổ Cây Nội Tại Atlas (Atlas Passive Tree Planner - 115+ Points):
- Tối đa hóa lợi nhuận tiền tệ (Currency Maximization) và duy trì tài nguyên bản đồ (Map Sustain).
- Phân kỳ 3 giai đoạn thăng tiến:
  * Giai đoạn 1 (Early Tier 1-5): Map Sustain & Tỷ lệ rơi Waystone cấp cao hơn (Points 1 - 35).
  * Giai đoạn 2 (Mid Tier 6-10): Pack Size, Quái vật Tinh anh (Rare Monsters) và Tích lũy Quỹ Vàng (Points 36 - 75).
  * Giai đoạn 3 (Endgame Tier 11-16): Tối đa hóa Divine/Mirror qua League Mechanics (Breach, Delirium, Ritual, Expedition) (Points 76 - 115+).
- Thuật toán phân bổ tự động (Auto Allocation Order) tuân thủ đồ thị phụ thuộc DAG (Prerequisites).

Tuân thủ nghiêm ngặt:
- Rule 1: Cold Path Tier 2 (Python 3.11).
- Rule 4: Module hóa độc lập, trần file < 500 dòng.
"""

from __future__ import annotations

import os
import tomllib
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Tuple


class TreePhase(str, Enum):
    """3 giai đoạn phân kỳ thăng tiến Cây Nội Tại Atlas."""
    PHASE_1_EARLY_SUSTAIN = "PHASE_1_EARLY_SUSTAIN"         # Points 1 - 35 (Tier 1-5 Sustain)
    PHASE_2_MID_QUANTITY_GOLD = "PHASE_2_MID_QUANTITY_GOLD" # Points 36 - 75 (Tier 6-10 Pack & Gold)
    PHASE_3_ENDGAME_MAX_PROFIT = "PHASE_3_ENDGAME_MAX_PROFIT" # Points 76 - 115+ (Tier 11-16 High Profit)


@dataclass
class AtlasPassiveNode:
    """Đỉnh của Cây Nội Tại Atlas biểu diễn một điểm kỹ năng."""
    node_id: str
    name: str
    phase: TreePhase
    priority_order: int                  # Thứ tự ưu tiên tăng dần từ 1 đến 115
    category: str                        # "Sustain", "PackSize", "Gold", "Breach", "Delirium", "Ritual", "Expedition"
    stat_description: str
    prerequisites: List[str] = field(default_factory=list) # Danh sách node_id bắt buộc học trước
    allocated: bool = False


class AtlasTreePlanner:
    """Bộ hoạch định và phân bổ Cây Nội Tại Atlas tự động tối ưu hóa lợi nhuận."""

    def __init__(self, toml_path: Optional[str] = "config/atlas_monk_ci_tree.toml"):
        self._nodes: Dict[str, AtlasPassiveNode] = {}
        self._allocation_sequence: List[str] = []
        loaded = False
        if toml_path and os.path.exists(toml_path):
            loaded = self._load_from_toml(toml_path)
        if not loaded:
            self._build_canonical_blueprint_115()

    def _load_from_toml(self, path: str) -> bool:
        """Nạp danh mục 115 đỉnh cây nội tại Atlas từ file cấu hình TOML độc lập (Doc 65 / Doc 70)."""
        try:
            with open(path, "rb") as f:
                data = tomllib.load(f)
            nodes_data = data.get("nodes", [])
            if not nodes_data:
                return False
            self._nodes.clear()
            self._allocation_sequence.clear()
            for raw in nodes_data:
                nid = raw["node_id"]
                node = AtlasPassiveNode(
                    node_id=nid,
                    name=raw["name"],
                    phase=TreePhase(raw["phase"]),
                    priority_order=int(raw["priority_order"]),
                    category=raw["category"],
                    stat_description=raw["stat_description"],
                    prerequisites=list(raw.get("prerequisites", [])),
                )
                self._nodes[nid] = node
                self._allocation_sequence.append(nid)
            return True
        except Exception:
            return False

    @property
    def total_nodes(self) -> int:
        return len(self._nodes)

    @property
    def allocated_count(self) -> int:
        return sum(1 for n in self._nodes.values() if n.allocated)

    def get_current_phase(self, points: Optional[int] = None) -> TreePhase:
        """Xác định giai đoạn thăng tiến dựa trên số điểm đã tích lũy."""
        pts = self.allocated_count if points is None else points
        if pts <= 35:
            return TreePhase.PHASE_1_EARLY_SUSTAIN
        elif pts <= 75:
            return TreePhase.PHASE_2_MID_QUANTITY_GOLD
        else:
            return TreePhase.PHASE_3_ENDGAME_MAX_PROFIT

    def _build_canonical_blueprint_115(self) -> None:
        """Xây dựng lộ trình 115 điểm nội tại chuẩn mực tối đa hóa lợi nhuận tiền tệ."""
        # ---------------------------------------------------------------------
        # GIAI ĐOẠN 1: Early Sustain (Points 1 -> 35)
        # Mục tiêu: Đảm bảo không bao giờ hết Waystones, nâng cấp tier bản đồ
        # ---------------------------------------------------------------------
        p1_specs = [
            ("sustain_root", "Atlas Gateway Root", "Sustain", "Điểm gốc khởi đầu cây nội tại Atlas", []),
            ("sustain_waystone_1", "Shaping the Valleys I", "Sustain", "+10% Chance for Waystones to drop 1 Tier higher", ["sustain_root"]),
            ("sustain_waystone_2", "Shaping the Valleys II", "Sustain", "+10% Chance for Waystones to drop 1 Tier higher", ["sustain_waystone_1"]),
            ("sustain_adjacent_1", "Frontier Scout I", "Sustain", "+15% Chance to drop connected adjacent Waystone", ["sustain_waystone_2"]),
            ("sustain_adjacent_2", "Frontier Scout II", "Sustain", "+15% Chance to drop connected adjacent Waystone", ["sustain_adjacent_1"]),
            ("sustain_notable_1", "Cartographer's Mastery", "Sustain", "Monsters drop +1 additional Waystone of current Tier", ["sustain_adjacent_2"]),
        ]
        # Thêm 29 điểm sustain nhỏ nối dài
        prev = "sustain_notable_1"
        for i in range(7, 36):
            nid = f"sustain_node_{i}"
            desc = f"+3% Waystone Drop Quantity and Map Quality (Rank {i})"
            p1_specs.append((nid, f"Endless Cartography {i}", "Sustain", desc, [prev]))
            prev = nid

        for idx, (nid, name, cat, desc, prereqs) in enumerate(p1_specs, start=1):
            self._nodes[nid] = AtlasPassiveNode(
                node_id=nid,
                name=name,
                phase=TreePhase.PHASE_1_EARLY_SUSTAIN,
                priority_order=idx,
                category=cat,
                stat_description=desc,
                prerequisites=prereqs,
            )
            self._allocation_sequence.append(nid)

        # ---------------------------------------------------------------------
        # GIAI ĐOẠN 2: Mid Pack Size & Gold Reserve (Points 36 -> 75)
        # Mục tiêu: Mật độ quái vật dày đặc, nhân đôi quái Rare và gom Vàng dồi dào
        # ---------------------------------------------------------------------
        p2_specs = [
            ("pack_connector", "Vast Legions Gateway", "PackSize", "Mở rộng nhánh mật độ quái vật", [prev]),
            ("pack_size_1", "Swarming Hordes I", "PackSize", "+4% Monster Pack Size in Maps", ["pack_connector"]),
            ("pack_size_2", "Swarming Hordes II", "PackSize", "+4% Monster Pack Size in Maps", ["pack_size_1"]),
            ("rare_quant_1", "Nemesis Infusion I", "PackSize", "+15% More Rare Monsters in Maps", ["pack_size_2"]),
            ("gold_find_1", "Kalguuran Taxes I", "Gold", "+25% Gold Dropped by Slain Monsters", ["rare_quant_1"]),
            ("gold_find_2", "Kalguuran Taxes II", "Gold", "+25% Gold Dropped by Slain Monsters", ["gold_find_1"]),
            ("gold_notable", "Faustus' Favor", "Gold", "Halves Gold Tax fee on Currency Exchange Market", ["gold_find_2"]),
        ]
        prev = "gold_notable"
        for i in range(43, 76):
            nid = f"mid_density_node_{i}"
            cat = "Gold" if i % 2 == 0 else "PackSize"
            desc = "+2% Pack Size and +15% Gold Multiplier" if cat == "Gold" else "+3% Magic/Rare Monster Pack Size"
            p2_specs.append((nid, f"Wealth & Density {i}", cat, desc, [prev]))
            prev = nid

        for idx, (nid, name, cat, desc, prereqs) in enumerate(p2_specs, start=36):
            self._nodes[nid] = AtlasPassiveNode(
                node_id=nid,
                name=name,
                phase=TreePhase.PHASE_2_MID_QUANTITY_GOLD,
                priority_order=idx,
                category=cat,
                stat_description=desc,
                prerequisites=prereqs,
            )
            self._allocation_sequence.append(nid)

        # ---------------------------------------------------------------------
        # GIAI ĐOẠN 3: Endgame High Profit League Mechanics (Points 76 -> 115)
        # Mục tiêu: Breach, Delirium, Ritual, Expedition tối đa hóa Divine & Mirror
        # ---------------------------------------------------------------------
        p3_specs = [
            ("endgame_gateway", "Outer Rim Nexus", "Expedition", "Cửa ngõ League Mechanics tối thượng", [prev]),
            ("breach_1", "Flash of the Realm", "Breach", "+30% Breach Open/Close Speed & +20% Splinters", ["endgame_gateway"]),
            ("breach_2", "Classified Portals", "Breach", "Breaches have +25% chance to contain an Additional Boss", ["breach_1"]),
            ("delirium_1", "Unending Nightmare", "Delirium", "Delirium Fog does not dissipate in maps", ["breach_2"]),
            ("delirium_2", "Paranoia Manifest", "Delirium", "+40% Cluster Jewels & Simulacrum Splinters", ["delirium_1"]),
            ("ritual_1", "Ominous Altars", "Ritual", "Rerolling Favors costs 30% less Tribute", ["delirium_2"]),
            ("ritual_2", "Blood Tribute", "Ritual", "Deferred items reappear 50% faster with high discount", ["ritual_1"]),
            ("expedition_1", "Dannig's Logbooks", "Expedition", "+40% Increased Logbook Drop Rate", ["ritual_2"]),
            ("expedition_2", "Ancient Kalguur Secrets", "Expedition", "Excavated Chests have +50% Item Quantity", ["expedition_1"]),
            ("pinnacle_apex", "Gaze of the Arbiter", "Pinnacle", "+100% Currency Drops from Citadel Bosses", ["expedition_2"]),
        ]
        prev = "pinnacle_apex"
        for i in range(86, 116):
            nid = f"apex_profit_node_{i}"
            cat_list = ["Breach", "Delirium", "Ritual", "Expedition"]
            cat = cat_list[i % len(cat_list)]
            desc = f"Apex {cat} Multiplier: +5% Chance to duplicate High Currency (Tier {i})"
            p3_specs.append((nid, f"Endgame Fortune {i}", cat, desc, [prev]))
            prev = nid

        for idx, (nid, name, cat, desc, prereqs) in enumerate(p3_specs, start=76):
            self._nodes[nid] = AtlasPassiveNode(
                node_id=nid,
                name=name,
                phase=TreePhase.PHASE_3_ENDGAME_MAX_PROFIT,
                priority_order=idx,
                category=cat,
                stat_description=desc,
                prerequisites=prereqs,
            )
            self._allocation_sequence.append(nid)

    def allocate_next_point(self) -> Optional[AtlasPassiveNode]:
        """
        Phân bổ tự động điểm tiếp theo theo đúng thứ tự DAG (Prerequisites) và priority_order.
        """
        for nid in self._allocation_sequence:
            node = self._nodes[nid]
            if not node.allocated:
                # Kiểm tra toàn bộ prerequisites đã được học chưa
                prereqs_met = all(self._nodes[p_id].allocated for p_id in node.prerequisites if p_id in self._nodes)
                if prereqs_met:
                    node.allocated = True
                    return node
        return None

    def allocate_batch(self, points_to_spend: int) -> List[AtlasPassiveNode]:
        """Phân bổ một đợt nhiều điểm nội tại liên tiếp."""
        allocated_nodes: List[AtlasPassiveNode] = []
        for _ in range(points_to_spend):
            node = self.allocate_next_point()
            if not node:
                break
            allocated_nodes.append(node)
        return allocated_nodes

    def reset_tree(self) -> None:
        """Đặt lại toàn bộ trạng thái phân bổ điểm."""
        for n in self._nodes.values():
            n.allocated = False

    def get_tree_stats(self) -> Dict[str, Any]:
        """Tính toán tổng hợp các chỉ số nội tại đã phân bổ."""
        allocated_nodes = [n for n in self._nodes.values() if n.allocated]
        total_pts = len(allocated_nodes)

        phase_counts = {
            TreePhase.PHASE_1_EARLY_SUSTAIN.value: 0,
            TreePhase.PHASE_2_MID_QUANTITY_GOLD.value: 0,
            TreePhase.PHASE_3_ENDGAME_MAX_PROFIT.value: 0,
        }
        category_counts: Dict[str, int] = {}

        for n in allocated_nodes:
            phase_counts[n.phase.value] += 1
            category_counts[n.category] = category_counts.get(n.category, 0) + 1

        return {
            "total_allocated_points": total_pts,
            "current_phase": self.get_current_phase(total_pts).value,
            "completion_pct": round((total_pts / max(1, self.total_nodes)) * 100.0, 1),
            "phase_distribution": phase_counts,
            "category_distribution": category_counts,
        }
