"""
Hệ Thống Tự Động Nhận Diện Giai Đoạn & Làm Quest Chiến Dịch (Dynamic Campaign Progression Runner)
Tự động xác định Act, nhận diện nhân vật đang ở đâu (Act 1, Act 2, Act 3, Town hay Combat Zone)
để tiếp nối nhiệm vụ dang dở mà không cần bắt đầu lại từ đầu.
"""

from dataclasses import dataclass
from enum import IntEnum
from typing import List, Optional


class MapScenario(IntEnum):
    BOSS_RUSH = 0          # Săn Boss nhanh mở điểm Atlas & qua map kế tiếp
    ATLAS_QUEST_RUSH = 1   # Ưu tiên thực thể nhiệm vụ Atlas / Citadel / Event
    FAST_CLEAR = 2         # Dọn nhanh quái Rare/Pack lớn trên đường chính
    FULL_CLEAR = 3         # Thám hiểm toàn bộ bản đồ


@dataclass
class QuestObjective:
    area_code: str
    area_name: str
    action_type: str        # "WAYPOINT", "TRANSITION", "BOSS", "NPC", "EXPLORE"
    target_name: str
    reward: str = ""        # "BOOK_OF_SKILL", "PASSIVE_POINT", etc.
    description: str = ""
    act: int = 1
    zone_index: int = 0     # Vị trí node phụ bản trên World Map giao diện U (0-indexed)

# Đồ thị tri thức chiến dịch POE2 (Act 1, Act 2, Act 3)
CAMPAIGN_KNOWLEDGE_GRAPH: List[QuestObjective] = [
    # ---- ACT 1: Ogham & Clearfell ----
    QuestObjective(
        area_code="G1_1",
        area_name="The Riverbank",
        action_type="TRANSITION",
        target_name="Clearfell Encampment",
        description="Đi dọc bờ sông tới thị trấn đầu tiên Clearfell Encampment",
        act=1,
        zone_index=0
    ),
    QuestObjective(
        area_code="Town_Act1",
        area_name="Clearfell Encampment",
        action_type="NPC",
        target_name="Una",
        reward="BOOK_OF_SKILL",
        description="Nhận nhiệm vụ và Book of Skill tăng điểm nội tại khởi đầu",
        act=1,
        zone_index=0
    ),
    QuestObjective(
        area_code="G1_2",
        area_name="The Ogham Farmlands",
        action_type="WAYPOINT",
        target_name="Ogham Waypoint",
        description="Mở khóa điểm dịch chuyển Farmlands",
        act=1,
        zone_index=1
    ),
    QuestObjective(
        area_code="G1_2",
        area_name="The Ogham Farmlands",
        action_type="BOSS",
        target_name="Crowbell",
        reward="BOOK_OF_SKILL",
        description="Tiêu diệt Boss Crowbell để nhận thêm điểm kỹ năng",
        act=1,
        zone_index=1
    ),
    QuestObjective(
        area_code="G1_3",
        area_name="The Hunting Grounds",
        action_type="WAYPOINT",
        target_name="Hunting Grounds Waypoint",
        description="Mở khóa điểm dịch chuyển khu rừng săn",
        act=1,
        zone_index=2
    ),
    QuestObjective(
        area_code="G1_3",
        area_name="The Hunting Grounds",
        action_type="TRANSITION",
        target_name="The Crypt",
        description="Tiến sâu vào hầm mộ The Crypt",
        act=1,
        zone_index=3
    ),
    QuestObjective(
        area_code="G1_4",
        area_name="The Crypt",
        action_type="BOSS",
        target_name="Crypt Boss",
        description="Quét hầm mộ và mở đường sang Tomb of the Consort",
        act=1,
        zone_index=3
    ),
    QuestObjective(
        area_code="G1_5",
        area_name="Tomb of the Consort",
        action_type="TRANSITION",
        target_name="Cemetery of the Eternals",
        description="Vượt qua lăng mộ Consort tiến về Nghĩa địa Bất tử",
        act=1,
        zone_index=3
    ),
    QuestObjective(
        area_code="G1_6",
        area_name="Cemetery of the Eternals",
        action_type="BOSS",
        target_name="Halani Boss",
        description="Hạ gục thủ lĩnh nghĩa địa để mở cổng Halani Gates",
        act=1,
        zone_index=3
    ),

    # ---- ACT 2: Vastiri & Ardura Caravan ----
    QuestObjective(
        area_code="G2_town",
        area_name="Ardura Caravan",
        action_type="NPC",
        target_name="Sekhema Asala",
        description="Hội đàm với Sekhema Asala và chuẩn bị vượt sa mạc Vastiri",
        act=2,
        zone_index=0
    ),
    QuestObjective(
        area_code="G2_1",
        area_name="Vastiri Outskirts",
        action_type="WAYPOINT",
        target_name="Vastiri Waypoint",
        description="Kích hoạt Waypoint rìa sa mạc Vastiri",
        act=2,
        zone_index=0
    ),
    QuestObjective(
        area_code="G2_2",
        area_name="The Mastodon Sands",
        action_type="BOSS",
        target_name="Sand Goliath",
        description="Tiêu diệt quái vật sa mạc khổng lồ Mastodon Sands",
        act=2,
        zone_index=1
    ),
    QuestObjective(
        area_code="G2_3",
        area_name="The Traitor's Passage",
        action_type="WAYPOINT",
        target_name="Traitor's Passage Waypoint",
        description="Mở khóa điểm dịch chuyển đường đèo kẻ phản bội",
        act=2,
        zone_index=2
    ),
    QuestObjective(
        area_code="G2_12",
        area_name="Dreadnought",
        action_type="BOSS",
        target_name="Jamanra, the Abomination",
        reward="BOOK_OF_SKILL",
        description="Quyết chiến Boss Jamanra (The Abomination) trên chiến hạm Dreadnought",
        act=2,
        zone_index=3
    ),

    # ---- ACT 3: The Sandswept Marsh & Phrey Jungle ----
    QuestObjective(
        area_code="G3_town",
        area_name="Phrey Jungle Encampment",
        action_type="NPC",
        target_name="Oswald / Act 3 Guide",
        description="Hội đàm với NPC tại Phrey Jungle Encampment nhận nhiệm vụ khám phá Act 3",
        act=3,
        zone_index=0
    ),
    QuestObjective(
        area_code="G3_1",
        area_name="Sandswept Marsh",
        action_type="WAYPOINT",
        target_name="Sandswept Marsh Waypoint",
        description="Mở khóa điểm dịch chuyển Sandswept Marsh (Waypoint, Level 33)",
        act=3,
        zone_index=0
    ),
    QuestObjective(
        area_code="G3_1",
        area_name="Sandswept Marsh",
        action_type="TRANSITION",
        target_name="Phrey Jungle",
        description="Tiêu diệt quái vật vùng đầm lầy Sandswept Marsh và tiến vào Phrey Jungle",
        act=3,
        zone_index=0
    ),
    QuestObjective(
        area_code="G3_2",
        area_name="Phrey Jungle",
        action_type="BOSS",
        target_name="Phrey Jungle Boss",
        description="Tiêu diệt Quest Boss tại Phrey Jungle và mở đường chuyển tiếp sang các khu vực tiếp theo",
        act=3,
        zone_index=1
    ),
    QuestObjective(
        area_code="G3_3",
        area_name="The Pools of Chakhir",
        action_type="WAYPOINT",
        target_name="Chakhir Waypoint",
        description="Kích hoạt điểm dịch chuyển The Pools of Chakhir",
        act=3,
        zone_index=2
    ),
    QuestObjective(
        area_code="G3_3",
        area_name="The Pools of Chakhir",
        action_type="BOSS",
        target_name="Chakhir Behemoth",
        reward="PASSIVE_POINT",
        description="Tiêu diệt quái thú Chakhir Behemoth nhận thêm điểm nội tại",
        act=3,
        zone_index=2
    ),
    QuestObjective(
        area_code="G3_4",
        area_name="The Matatl Grounds",
        action_type="WAYPOINT",
        target_name="Matatl Waypoint",
        description="Mở khóa điểm dịch chuyển The Matatl Grounds",
        act=3,
        zone_index=3
    ),
    QuestObjective(
        area_code="G3_5",
        area_name="The Ziggurat / Aggorat",
        action_type="BOSS",
        target_name="Vaal Overseer / Doryani",
        reward="BOOK_OF_SKILL",
        description="Quyết chiến Boss Vaal Overseer tại The Ziggurat / Aggorat nhận Book of Skill Act 3",
        act=3,
        zone_index=4
    ),
]

class AutoQuester:
    # Các UI scene overlay hoặc giá trị không hợp lệ không được coi là map
    INVALID_MAP_NAMES = frozenset({
        "act 1",
        "act 2",
        "act 3",
        "act 4",
        "atlas",
        "(null)",
        "(unknown)",
    })

    def __init__(self) -> None:
        self.roadmap: List[QuestObjective] = CAMPAIGN_KNOWLEDGE_GRAPH
        self.current_step_index = 0
        self.completed_objectives: List[str] = []
        self.skill_books_consumed = 0
        self.scenario: MapScenario = MapScenario.BOSS_RUSH
        self.auto_portal_after_boss: bool = True

    def set_map_scenario(self, scenario: MapScenario, auto_portal: bool = True) -> None:
        """Thiết lập kịch bản vận hành trong map (Boss Rush, Atlas Quest, Fast Clear, Full Clear)."""
        self.scenario = scenario
        self.auto_portal_after_boss = auto_portal

    def is_hideout_area(self, area_code: str = "", area_name: str = "") -> bool:
        """Nhận diện xem khu vực có phải là Hideout (Endgame Hub) hay không."""
        c = (area_code or "").lower().strip()
        n = (area_name or "").lower().strip()
        if n.startswith("đã chuyển đến khu vực:"):
            n = n.split(":", 1)[1].strip()
        return "hideout" in c or "hideout" in n

    def is_endgame_map(self, area_code: str = "", area_name: str = "", area_level: int = 1) -> bool:
        """
        Kiểm tra xem khu vực hiện tại có phải là Map Endgame (Waystones / Atlas) không.
        - Level >= 65
        - Mã khu vực hoặc tên khu vực chứa: 'mapworlds', 'endgame', 'waystone', 'tier', 'atlas', 'citadel', 'pinnacle', 'hideout'
        - Không phải thị trấn / Encampment
        """
        # Nếu gọi với 1 đối số (truyền tên map trực tiếp)
        if not area_name and area_code and (" " in area_code or any(k in area_code.lower() for k in ("map", "tier", "atlas", "waystone", "citadel", "hideout"))):
            area_name = area_code

        if self.is_hideout_area(area_code, area_name):
            return True

        if self.is_town_area(area_code, area_name):
            return False
        c = (area_code or "").lower().strip()
        n = (area_name or "").lower().strip()
        if n.startswith("đã chuyển đến khu vực:"):
            n = n.split(":", 1)[1].strip()

        return (
            area_level >= 65
            or "mapworlds" in c
            or "endgame" in c
            or "atlas" in c
            or "waystone" in n
            or "atlas" in n
            or "citadel" in n
            or "pinnacle" in n
            or "tier " in n
            or (c.startswith("map") and not c.startswith("map_act"))
        )

    def is_valid_map_name(self, area_name: str) -> bool:
        """
        Kiểm tra xem tên khu vực có phải là map hợp lệ hay không.
        Bỏ qua các UI scene/overlay như Act 1, Act 2, Act 3, Act 4, Atlas, (null), (unknown).
        """
        if not area_name:
            return False
        clean = area_name.strip().lower()
        if clean.startswith("đã chuyển đến khu vực:"):
            clean = clean.split(":", 1)[1].strip()
        return clean not in self.INVALID_MAP_NAMES

    def is_town_area(self, area_code: str, area_name: str) -> bool:
        """
        Nhận diện xem khu vực hiện tại có phải là Thị trấn / Encampment an toàn hay không.
        - Act 1: Clearfell Encampment (Town_Act1, G1_town)
        - Act 2: Ardura Caravan (G2_town)
        - Act 3: G3_town hoặc khu vực có từ khóa: "encampment", "the haven", "caravan", "hideout".
        Lưu ý đặc biệt: Sandswept Marsh (G3_1) là map chiến đấu Level 33, hoàn toàn KHÔNG PHẢI là Thành/Thị trấn!
        Các UI scene overlay: "Act 1", "Act 2", "Act 3", "Act 4", "Atlas" tuyệt đối KHÔNG phải là Thị trấn.
        """
        c = (area_code or "").lower().strip()
        n = (area_name or "").lower().strip()
        if n.startswith("đã chuyển đến khu vực:"):
            n = n.split(":", 1)[1].strip()

        # UI Scene overlay và tên map không hợp lệ tuyệt đối không phải là thị trấn
        if n in self.INVALID_MAP_NAMES:
            return False

        # Sandswept Marsh (G3_1) là Map chiến đấu Level 33, tuyệt đối không phải thị trấn
        if c == "g3_1" or n == "sandswept marsh" or n == "the sandswept marsh":
            return False

        return (
            "town" in c
            or "g3_town" in c
            or c == "g3"
            or ("g3" in c and "town" in c)
            or "encampment" in n
            or "the haven" in n
            or "haven" in n
            or "caravan" in n
            or "hideout" in n
            or "g3_town" in n
        )

    def resolve_active_objective(self, current_area_code: str = "", current_area_name: str = "", area_level: int = 1) -> QuestObjective:
        """
        Nhận diện thông minh giai đoạn nhân vật đang đứng:
        1. Lọc bỏ các tên map không hợp lệ (UI overlay scenes: Act 1, Act 2, Act 3, Act 4, Atlas).
        2. Xử lý ưu tiên Map chiến đấu Sandswept Marsh (G3_1, Lv 33).
        3. Tìm trong Knowledge Graph xem map hiện tại có mục tiêu chiến dịch cụ thể nào không.
        4. Nếu ở Town / Hideout: Hướng dẫn tìm NPC hoặc Waypoint.
        5. Nếu ở Leveling Zone tự do: Tạo mục tiêu động (Khám phá -> Mở Waypoint -> Diệt Boss -> Sang map kế).
        """
        if not current_area_name and current_area_code and (" " in current_area_code or any(k in current_area_code.lower() for k in ("map", "tier", "atlas", "waystone", "citadel", "farmlands", "riverbank", "sandswept", "marsh"))):
            current_area_name = current_area_code

        code = current_area_code or ""
        name = current_area_name or ""
        if not self.is_valid_map_name(name):
            name = ""

        code_lower = code.lower().strip()
        name_lower = name.lower().strip()
        if name_lower.startswith("đã chuyển đến khu vực:"):
            name_lower = name_lower.split(":", 1)[1].strip()
            name = name.split(":", 1)[1].strip()

        # 0. Ưu tiên nhận diện Map chiến đấu Sandswept Marsh (G3_1, Lv 33):
        # Trả về mục tiêu chiến đấu của Sandswept Marsh (mở Waypoint / diệt quái / sang Phrey Jungle)
        if code_lower == "g3_1" or "sandswept" in name_lower:
            if "Sandswept Marsh Waypoint" in self.completed_objectives:
                return QuestObjective(
                    area_code="G3_1",
                    area_name="Sandswept Marsh",
                    action_type="TRANSITION",
                    target_name="Phrey Jungle",
                    description="Tiêu diệt quái vật vùng đầm lầy Sandswept Marsh và tiến vào Phrey Jungle",
                    act=3,
                    zone_index=0
                )
            return QuestObjective(
                area_code="G3_1",
                area_name="Sandswept Marsh",
                action_type="WAYPOINT",
                target_name="Sandswept Marsh Waypoint",
                description="Mở khóa điểm dịch chuyển Sandswept Marsh (Waypoint, Level 33), diệt quái và mở đường sang Phrey Jungle",
                act=3,
                zone_index=0
            )

        # 0b. Nhận diện Hideout (Endgame Hub):
        if self.is_hideout_area(code, name):
            return QuestObjective(
                area_code=code or "Hideout",
                area_name=name or "Shoreline Hideout",
                action_type="MAP_DEVICE",
                target_name="Endgame Map Device",
                reward="WAYSTONE_EARNINGS",
                description="Hideout: Nạp Waystone vào Map Device, click TRAVERSE mở cổng Endgame!",
                act=4,
                zone_index=0
            )

        # 0c. Nhận diện Map Endgame (Waystones / Atlas Progression):
        if self.is_endgame_map(code, name, area_level):
            tier = max(1, area_level - 64) if area_level >= 65 else 1
            map_display = name or f"Waystone Map Tier {tier}"
            if self.scenario == MapScenario.BOSS_RUSH:
                return QuestObjective(
                    area_code=code,
                    area_name=map_display,
                    action_type="BOSS_RUSH",
                    target_name="Map Boss / Arena Entrance",
                    reward="ATLAS_POINT",
                    description="Săn Boss Thần Tốc: Bỏ qua quái rác, hạ Boss map mở điểm Atlas rồi mở Portal về Hideout!",
                    act=4,
                    zone_index=0
                )
            elif self.scenario == MapScenario.ATLAS_QUEST_RUSH:
                return QuestObjective(
                    area_code=code,
                    area_name=map_display,
                    action_type="ATLAS_QUEST",
                    target_name="Citadel / Atlas Event",
                    reward="ATLAS_PASSIVE",
                    description="Nhiệm Vụ Atlas: Tìm thực thể nhiệm vụ/Citadel, hoàn thành sự kiện rồi diệt Boss!",
                    act=4,
                    zone_index=0
                )
            elif self.scenario == MapScenario.FAST_CLEAR:
                return QuestObjective(
                    area_code=code,
                    area_name=map_display,
                    action_type="FAST_CLEAR",
                    target_name="Rare Packs & Boss",
                    reward="EXP_AND_LOOT",
                    description="Dọn Nhanh Tuyến Chính: Tiêu diệt quái Rare/Pack lớn trên đường tới Boss!",
                    act=4,
                    zone_index=0
                )
            else:
                return QuestObjective(
                    area_code=code,
                    area_name=map_display,
                    action_type="FULL_CLEAR",
                    target_name="All Monsters & Boss",
                    reward="FULL_CLEAR",
                    description="Thám Hiểm Toàn Bản Đồ: Dò sạch sương mù bản đồ theo Frontier Momentum A*!",
                    act=4,
                    zone_index=0
                )

        # 1. Tìm khớp trực tiếp trong cơ sở dữ liệu
        # Khớp theo mã khu vực trước
        for step in self.roadmap:
            if step.target_name not in self.completed_objectives:
                if step.area_code and code_lower and step.area_code.lower() == code_lower:
                    return step

        # Khớp theo tên khu vực
        for step in self.roadmap:
            if step.target_name not in self.completed_objectives:
                if step.area_name and name_lower:
                    step_name_lower = step.area_name.lower()
                    if step_name_lower in name_lower or (len(name_lower) >= 4 and name_lower in step_name_lower):
                        return step

        # Phân loại Act chuẩn xác:
        # Nếu code chứa "g3" hoặc name chứa "act 3" hoặc "sandswept" -> Xác định chuẩn xác act = 3
        if (
            "g3" in code_lower
            or "act 3" in name_lower
            or "act3" in name_lower
            or "act_3" in name_lower
            or "sandswept" in name_lower
            or "phrey" in name_lower
            or "chakhir" in name_lower
            or "matatl" in name_lower
            or "ziggurat" in name_lower
            or "aggorat" in name_lower
        ):
            detected_act = 3
        elif (
            "g2" in code_lower
            or "act 2" in name_lower
            or "act2" in name_lower
            or "act_2" in name_lower
            or "ardura" in name_lower
            or "vastiri" in name_lower
            or "mastodon" in name_lower
            or "traitor" in name_lower
            or "dreadnought" in name_lower
        ):
            detected_act = 2
        elif (
            "g1" in code_lower
            or "act 1" in name_lower
            or "act1" in name_lower
            or "act_1" in name_lower
            or "clearfell" in name_lower
            or "ogham" in name_lower
            or "riverbank" in name_lower
            or "hunting grounds" in name_lower
            or "crypt" in name_lower
        ):
            detected_act = 1
        elif area_level >= 45:
            detected_act = 3
        elif area_level >= 25:
            detected_act = 2
        else:
            detected_act = 1

        # 2. Xử lý khi ở Thành / Thị trấn
        if self.is_town_area(code, name):
            # Tìm mục tiêu tiếp theo chưa hoàn thành trong đồ thị chiến dịch cho Act này
            for step in self.roadmap:
                if step.act == detected_act and step.target_name not in self.completed_objectives:
                    return step

            # Nếu đã hoàn thành hết quest của Act này, tìm quest chưa xong ở Act tiếp theo
            for step in self.roadmap:
                if step.target_name not in self.completed_objectives:
                    return step

            return QuestObjective(
                area_code=code,
                area_name=name or f"Act {detected_act} Encampment",
                action_type="NPC",
                target_name="Quest NPC / Waypoint",
                description=f"Thị trấn Act {detected_act}: Tương tác với NPC nhiệm vụ hoặc ra Waypoint dịch chuyển tới map đang làm",
                act=detected_act,
                zone_index=0
            )

        # 3. Xử lý Map Chiến Đấu Tổng Quát (Dynamic Zone Runner)
        return QuestObjective(
            area_code=code,
            area_name=name or f"Zone Lv {area_level}",
            action_type="EXPLORE",
            target_name="Waypoint / Boss / Portal",
            description=f"Map Chiến Đấu Act {detected_act} (Lv {area_level}): Mở Waypoint, tiêu diệt Boss/Unique và tìm cổng chuyển cảnh",
            act=detected_act,
            zone_index=0
        )

    def get_current_objective(self, current_area_code: str, current_area_name: str) -> Optional[QuestObjective]:
        """Tương thích ngược với mã nguồn cũ."""
        return self.resolve_active_objective(current_area_code, current_area_name, 1)

    def record_objective_completed(self, target_name: str, reward: str = ""):
        """Ghi nhận hoàn thành mục tiêu nhiệm vụ."""
        if target_name not in self.completed_objectives:
            self.completed_objectives.append(target_name)
            if reward == "BOOK_OF_SKILL":
                self.skill_books_consumed += 1

    def get_status_banner(self, current_area_code: str = "", current_area_name: str = "", area_level: int = 1) -> str:
        """Chuỗi hiển thị trên Overlay và GUI theo thời gian thực."""
        if isinstance(current_area_name, int) and area_level == 1:
            area_level = current_area_name
            current_area_name = current_area_code
            current_area_code = ""

        cur = self.resolve_active_objective(current_area_code, current_area_name, area_level)
        scenario_tag = f"[{self.scenario.name.replace('_', ' ')}]"
        if cur.act == 4 or self.is_endgame_map(current_area_code, current_area_name, area_level):
            tier = max(1, area_level - 64) if area_level >= 65 else 1
            return f">> [ATLAS ENDGAME {scenario_tag}] [Tier {tier}] {cur.area_name}: {cur.action_type} -> {cur.target_name} ({cur.description})"
        return f">> [QUEST {scenario_tag}] [Act {cur.act}] {cur.area_name}: {cur.action_type} -> {cur.target_name} ({cur.description})"

    def get_objectives_for_act(self, act: int) -> List[QuestObjective]:
        """Lấy danh sách các mục tiêu nhiệm vụ theo Act."""
        return [step for step in self.roadmap if step.act == act]

    def trigger_world_map_travel(self, core_bridge, act: int, zone_index: int) -> bool:
        """Kích hoạt lệnh dịch chuyển World Map qua phím U tới Act và Zone mục tiêu."""
        if core_bridge and hasattr(core_bridge, "send_trigger_world_map_travel"):
            return bool(core_bridge.send_trigger_world_map_travel(act, zone_index))
        return False

