"""
Poe2VisualTool Universal Item Inspector & Parser
Phân tích văn bản thẻ vật phẩm (Item Tooltip Text) từ clipboard POE2 (v0.5.5+).
Nhận diện Item Class, Rarity, Item Level, Quality, Sockets, Requirements.
Bóc tách Advanced Mod tags { Prefix / Suffix Modifier ... (Tier: X) } hoặc phân loại Prefix/Suffix qua danh mục regex.
Tính toán chính xác Open Prefixes, Open Suffixes phục vụ chế đồ / đập Rune.
Tích hợp ModifierFilter đánh giá Waystone (Brick / Dangerous / Reward).
Đánh giá trang bị, vũ khí, trang sức, bùa ngọc và bình flask.
100% Zero-Disk, Zero-Memory-Write, Zero-Ban risk.
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional, Tuple

from src.assistant.modifier_filter import (
    ModifierFilter,
    ModReport,
    ModSeverity,
    evaluate_modifiers,
)


class ItemCategory(Enum):
    WAYSTONE = "WAYSTONE"
    WEAPON = "WEAPON"
    BODY_ARMOUR = "BODY_ARMOUR"
    HELMET = "HELMET"
    BOOTS = "BOOTS"
    GLOVES = "GLOVES"
    SHIELD = "SHIELD"
    QUIVER = "QUIVER"
    RING = "RING"
    AMULET = "AMULET"
    BELT = "BELT"
    JEWEL = "JEWEL"
    CHARM = "CHARM"
    FLASK = "FLASK"
    CURRENCY = "CURRENCY"
    OTHER = "OTHER"


class ItemRarity(Enum):
    NORMAL = "NORMAL"
    MAGIC = "MAGIC"
    RARE = "RARE"
    UNIQUE = "UNIQUE"


class AffixType(Enum):
    PREFIX = "PREFIX"
    SUFFIX = "SUFFIX"
    IMPLICIT = "IMPLICIT"
    UNKNOWN = "UNKNOWN"


class InspectionSeverity(Enum):
    BRICK = "BRICK"          # Đỏ đậm: làm hỏng build / chắc chắn tử trận
    DANGEROUS = "DANGEROUS"  # Đỏ: nguy hiểm cao
    NEUTRAL = "NEUTRAL"      # Trắng: thuộc tính bình thường
    CRAFTING = "CRAFTING"    # Vàng/Tím: tiềm năng chế đồ, open affix slot
    REWARD = "REWARD"        # Xanh lá: mod xịn, tăng thưởng map
    GOD_ROLL = "GOD_ROLL"    # Xanh lá đậm: mod đỉnh cao (T1/God Roll)


@dataclass
class InspectionMod:
    text: str
    affix_type: AffixType = AffixType.UNKNOWN
    severity: InspectionSeverity = InspectionSeverity.NEUTRAL
    category: str = ""
    description: str = ""
    tier: Optional[int] = None
    color_code: str = ""
    original_order: int = 0


OrderedModifierItem = InspectionMod


@dataclass
class ItemInspectionReport:
    item_name: str = ""
    item_class: str = ""
    base_type: str = ""
    category: ItemCategory = ItemCategory.OTHER
    rarity: ItemRarity = ItemRarity.NORMAL
    item_level: int = 0
    quality: int = 0
    is_brick: bool = False
    safety_score: int = 100
    quality_score: int = 0
    green_mods: List[str] = field(default_factory=list)
    yellow_mods: List[str] = field(default_factory=list)
    red_mods: List[str] = field(default_factory=list)
    neutral_mods: List[str] = field(default_factory=list)
    open_prefixes: int = 0
    open_suffixes: int = 0
    max_prefixes: int = 0
    max_suffixes: int = 0
    summary: str = ""
    raw_mods: List[InspectionMod] = field(default_factory=list)
    ordered_modifiers: List[InspectionMod] = field(default_factory=list)
    properties: List[str] = field(default_factory=list)


@dataclass
class ParsedItemData:
    item_class: str = ""
    rarity: str = "Normal"
    name: str = ""
    base_type: str = ""
    quality: int = 0
    item_level: int = 0
    requirements: Dict[str, str] = field(default_factory=dict)
    sockets: str = ""
    is_corrupted: bool = False
    implicit_lines: List[str] = field(default_factory=list)
    explicit_lines: List[Tuple[str, Optional[AffixType], Optional[int], str]] = field(default_factory=list)
    ordered_lines: List[Tuple[str, AffixType, Optional[int], str]] = field(default_factory=list)
    properties: List[str] = field(default_factory=list)
    raw_sections: List[List[str]] = field(default_factory=list)


class UniversalItemParser:
    """
    Bộ phân tích clipboard text POE2 theo các khối phân tách bởi '--------'.
    Nhận diện Item Class, Rarity, Tên đồ, Base Type, Quality, Item Level, Requirements, Sockets.
    Nhận diện Advanced Mod tags:
      { Prefix Modifier "..." (Tier: X) }
      { Suffix Modifier "..." (Tier: X) }
    Nếu không có tag, tự động phân loại dựa trên danh mục regex chuẩn POE2.
    """

    RE_CLASS = re.compile(r"^Item Class:\s*(.+)$", re.I)
    RE_RARITY = re.compile(r"^Rarity:\s*(.+)$", re.I)
    RE_QUALITY = re.compile(r"^Quality:\s*\+?(\d+)%", re.I)
    RE_ILVL = re.compile(r"^Item Level:\s*(\d+)$", re.I)
    RE_SOCKETS = re.compile(r"^Sockets:\s*(.+)$", re.I)
    RE_ADV_TAG = re.compile(
        r"^\{\s*(Prefix|Suffix|Implicit)\s+Modifier\s+\"([^\"]*)\"(?:\s*\(Tier:\s*(\d+)\))?.*?\}",
        re.I,
    )

    # Danh mục Regex chuẩn xác định Tiền tố (Prefix) trên trang bị POE2
    PREFIX_REGEXES = [
        # Máu & Máu %
        re.compile(r"^\+?\d+%?\s+to\s+maximum\s+Life", re.I),
        re.compile(r"^\d+%\s+increased\s+maximum\s+Life", re.I),
        # Mana & Mana %
        re.compile(r"^\+?\d+%?\s+to\s+maximum\s+Mana", re.I),
        re.compile(r"^\d+%\s+increased\s+maximum\s+Mana", re.I),
        # Spirit
        re.compile(r"^\+\d+\s+to\s+maximum\s+Spirit", re.I),
        # Giáp, Né tránh, Khiên năng lượng, Hộ giáp (Flat & %)
        re.compile(r"^\+\d+\s+to\s+(?:Armour|Evasion(?:\s+Rating)?|Energy\s+Shield|Ward)", re.I),
        re.compile(r"^\d+%\s+increased\s+(?:Armour|Evasion(?:\s+Rating)?|Energy\s+Shield|Ward)", re.I),
        re.compile(r"^\+\d+\s+to\s+Armour\s+and\s+(?:Energy\s+Shield|Evasion)", re.I),
        re.compile(r"^\+\d+\s+to\s+Evasion\s+and\s+Energy\s+Shield", re.I),
        # Sát thương cộng thêm (Added Flat Phys / Ele / Chaos)
        re.compile(r"^Adds\s+\d+\s+to\s+\d+\s+(?:Physical|Fire|Cold|Lightning|Chaos)\s+Damage", re.I),
        # Tăng % Sát thương (Increased Phys / Spell / Elemental Damage)
        re.compile(r"^\d+%\s+increased\s+(?:Physical\s+Damage|Spell\s+Damage|Elemental\s+Damage)", re.I),
        # Tăng cấp độ Gem kỹ năng (+Skill Gems)
        re.compile(r"^\+\d+\s+to\s+Level\s+of\s+(?:all\s+)?(?:\w+\s+)?(?:Skill\s+)?Gems", re.I),
        # Tốc chạy trên giày (Movement Speed)
        re.compile(r"^\d+%\s+increased\s+Movement\s+Speed", re.I),
        # Hút máu / Mana (Leech)
        re.compile(r"^\d+(?:\.\d+)?%\s+of\s+(?:Physical\s+)?Damage\s+Leeched\s+as\s+(?:Life|Mana)", re.I),
        # Thu hồi bình / Flask Recovery
        re.compile(r"^\d+%\s+increased\s+(?:Life|Mana)\s+Recovered", re.I),
        re.compile(r"^Recovers\s+\d+\s+(?:Life|Mana)", re.I),
    ]

    # Danh mục Regex chuẩn xác định Hậu tố (Suffix) trên trang bị POE2
    SUFFIX_REGEXES = [
        # Các loại Kháng (Fire, Cold, Lightning, Chaos, All Elemental)
        re.compile(r"^\+\d+%\s+to\s+(?:Fire|Cold|Lightning|Chaos|all\s+Elemental)\s+Resistances?", re.I),
        re.compile(r"^\+\d+%\s+to\s+(?:Fire\s+and\s+Cold|Cold\s+and\s+Lightning|Fire\s+and\s+Lightning)\s+Resistances?", re.I),
        # Thuộc tính nhân vật (Strength, Dexterity, Intelligence, All Attributes)
        re.compile(r"^\+\d+\s+to\s+(?:Strength|Dexterity|Intelligence|all\s+Attributes)", re.I),
        # Chí mạng (Critical Strike Chance & Multiplier)
        re.compile(r"^\d+%\s+increased\s+(?:Global\s+)?Critical\s+Strike\s+Chance", re.I),
        re.compile(r"^\+\d+%\s+to\s+(?:Global\s+)?Critical\s+Strike\s+Multiplier", re.I),
        # Tốc độ đánh & Tốc độ thi triển (Attack Speed & Cast Speed)
        re.compile(r"^\d+%\s+increased\s+(?:Attack|Cast)\s+Speed", re.I),
        # Độ chính xác (Accuracy Rating)
        re.compile(r"^\+\d+\s+to\s+Accuracy\s+Rating", re.I),
        re.compile(r"^\d+%\s+increased\s+Accuracy\s+Rating", re.I),
        # Kháng phép / Giảm sát thương phép (Spell Suppression)
        re.compile(r"^\+?\d+%\s+chance\s+to\s+Suppress\s+Spell\s+Damage", re.I),
        # Hồi phục Máu / Mana mỗi giây (Regeneration)
        re.compile(r"^Regenerate\s+\d+(?:\.\d+)?\s+Life\s+per\s+second", re.I),
        re.compile(r"^\d+%\s+increased\s+Mana\s+Regeneration\s+Rate", re.I),
        # Tăng độ hiếm đồ rơi (Rarity of Items found)
        re.compile(r"^\d+%\s+increased\s+Rarity\s+of\s+Items\s+found", re.I),
        # Giảm yêu cầu chỉ số / Phục hồi choáng (Reduced Requirements / Stun Recovery)
        re.compile(r"^\d+%\s+reduced\s+Attribute\s+Requirements", re.I),
        re.compile(r"^\d+%\s+increased\s+Stun\s+and\s+Block\s+Recovery", re.I),
        # Miễn nhiễm / Giảm thời gian hiệu ứng xấu (Ailments)
        re.compile(r"^\d+%\s+chance\s+to\s+Avoid\s+being\s+(?:Frozen|Shocked|Ignited|Stunned|Chilled)", re.I),
        re.compile(r"^Grants\s+Immunity\s+to\s+\w+", re.I),
        # Tiêu hao charges bình máu / flask
        re.compile(r"^\d+%\s+reduced\s+Flask\s+Charges\s+used", re.I),
        re.compile(r"^\d+%\s+increased\s+Flask\s+Charges\s+gained", re.I),
        re.compile(r"^\d+%\s+increased\s+Flask\s+Duration", re.I),
    ]

    @classmethod
    def parse(cls, raw_text: str) -> Optional[ParsedItemData]:
        """Phân tích văn bản clipboard POE2 thành cấu trúc ParsedItemData."""
        if not raw_text or not raw_text.strip():
            return None

        # Kiểm tra điều kiện tiên quyết: phải có "Item Class:" hoặc "Rarity:"
        if "Item Class:" not in raw_text and "Rarity:" not in raw_text:
            return None

        clean_text = raw_text.replace("\r\n", "\n").strip()
        raw_sections = [
            [line.strip() for line in sec.strip().splitlines() if line.strip()]
            for sec in clean_text.split("--------")
        ]
        # Loại bỏ các section rỗng
        sections = [s for s in raw_sections if s]
        if not sections:
            return None

        data = ParsedItemData(raw_sections=sections)

        # 1. Bóc tách Header (Section 0)
        header_lines = sections[0]
        for line in header_lines:
            m_class = cls.RE_CLASS.match(line)
            if m_class:
                data.item_class = m_class.group(1).strip()
                continue
            m_rarity = cls.RE_RARITY.match(line)
            if m_rarity:
                data.rarity = m_rarity.group(1).strip()
                continue

        # Xác định Tên đồ và Base Type
        # Header thường có dạng:
        # Line 0: Item Class: ...
        # Line 1: Rarity: ...
        # Line 2: Item Name (nếu Rare/Unique) hoặc Base Type (nếu Normal/Magic)
        # Line 3: Base Type (nếu Rare/Unique)
        non_meta_lines = [
            ln for ln in header_lines
            if not cls.RE_CLASS.match(ln) and not cls.RE_RARITY.match(ln)
        ]

        if data.rarity.lower() in ["rare", "unique"]:
            if len(non_meta_lines) >= 2:
                data.name = non_meta_lines[0]
                data.base_type = non_meta_lines[1]
            elif len(non_meta_lines) == 1:
                data.name = non_meta_lines[0]
                data.base_type = non_meta_lines[0]
        else:
            if non_meta_lines:
                data.base_type = non_meta_lines[-1]
                data.name = non_meta_lines[0]

        # 2. Bóc tách các section tiếp theo
        current_adv_tag: Optional[Tuple[AffixType, Optional[int], str]] = None
        seen_item_level = False

        for section in sections[1:]:
            # Kiểm tra các khối metadata đặc biệt
            sec_text = "\n".join(section)

            # Requirements
            if any(ln.startswith("Requirements:") for ln in section):
                for ln in section[1:]:
                    parts = ln.split(":", 1)
                    if len(parts) == 2:
                        data.requirements[parts[0].strip()] = parts[1].strip()
                continue

            # Sockets
            if any(ln.startswith("Sockets:") for ln in section):
                for ln in section:
                    m_sock = cls.RE_SOCKETS.match(ln)
                    if m_sock:
                        data.sockets = m_sock.group(1).strip()
                continue

            # Item Level
            if any(ln.startswith("Item Level:") for ln in section):
                seen_item_level = True
                for ln in section:
                    m_ilvl = cls.RE_ILVL.match(ln)
                    if m_ilvl:
                        data.item_level = int(m_ilvl.group(1))
                continue

            # Status Flags
            if "Corrupted" in section:
                data.is_corrupted = True

            # Duyệt từng dòng trong section để tìm Quality và Mods
            for line in section:
                # Quality
                m_qual = cls.RE_QUALITY.match(line)
                if m_qual:
                    data.quality = int(m_qual.group(1))
                    continue

                # Bỏ qua các dòng trạng thái hoặc metadata cơ bản
                if line in ["Corrupted", "Mirrored", "Unidentified"]:
                    continue
                if any(line.startswith(p) for p in [
                    "Armour:", "Evasion Rating:", "Energy Shield:", "Ward:",
                    "Physical Damage:", "Elemental Damage:", "Critical Strike Chance:",
                    "Attacks per Second:", "Reload Time:", "Recovers ", "Waystone Tier:",
                ]):
                    continue

                # Bỏ qua flavor text / instruction text
                if any(line.startswith(flv) for flv in [
                    "Can be used in a Map Device", "Place into an empty Map Device",
                    "Right click to", "Shift click to", "Take into a map to discover"
                ]):
                    continue

                # Nhận diện Advanced Mod Tag: { Prefix Modifier "..." (Tier: X) }
                m_adv = cls.RE_ADV_TAG.match(line)
                if m_adv:
                    affix_str, mod_name, tier_str = m_adv.group(1).upper(), m_adv.group(2), m_adv.group(3)
                    affix_type = AffixType.PREFIX if affix_str == "PREFIX" else (
                        AffixType.SUFFIX if affix_str == "SUFFIX" else AffixType.IMPLICIT
                    )
                    tier = int(tier_str) if tier_str else None
                    current_adv_tag = (affix_type, tier, mod_name)
                    continue

                # Bỏ hậu tố ' (augmented)' nếu có từ clipboard
                clean_line = re.sub(r"\s*\(augmented\)$", "", line, flags=re.I).strip()

                # Implicit Mod nhận diện qua nhãn "(implicit)"
                if "(implicit)" in line:
                    clean_line = clean_line.replace("(implicit)", "").strip()
                    data.implicit_lines.append(clean_line)
                    data.ordered_lines.append((clean_line, AffixType.IMPLICIT, None, ""))
                    continue

                # Các thuộc tính nằm trước Item Level trên Waystone (Revives, Pack Size, Rarity, Drop Chance)
                is_waystone = data.item_class.lower().startswith("waystone") or "waystone" in data.base_type.lower() or "waystone" in data.name.lower()
                if not seen_item_level and is_waystone:
                    data.implicit_lines.append(clean_line)
                    data.ordered_lines.append((clean_line, AffixType.IMPLICIT, None, ""))
                    continue

                # Explicit Mod line
                if current_adv_tag:
                    affix_type, tier, mod_name = current_adv_tag
                    data.explicit_lines.append((clean_line, affix_type, tier, mod_name))
                    data.ordered_lines.append((clean_line, affix_type, tier, mod_name))
                    current_adv_tag = None
                else:
                    # Không có Advanced tag: tự phân loại bằng Regex
                    guessed_type = cls.classify_affix(clean_line)
                    data.explicit_lines.append((clean_line, guessed_type, None, ""))
                    data.ordered_lines.append((clean_line, guessed_type, None, ""))

        return data

    @classmethod
    def classify_affix(cls, line: str) -> AffixType:
        """Phân loại Prefix hoặc Suffix dựa trên danh mục Regex chuẩn."""
        for pattern in cls.PREFIX_REGEXES:
            if pattern.search(line):
                return AffixType.PREFIX
        for pattern in cls.SUFFIX_REGEXES:
            if pattern.search(line):
                return AffixType.SUFFIX
        return AffixType.UNKNOWN


class UniversalItemInspector:
    """
    Bộ đánh giá vật phẩm POE2 toàn diện:
    - Waystones: Tích hợp ModifierFilter (Reflect, No Leech, No Regen, Quant, Rarity, Pack Size).
    - Trang bị / Vũ khí: Chấm điểm Máu (>=80, >=110 God Roll), Kháng (>=35 đơn, >=20 All/Chaos),
      Tốc chạy (>=25, >=30 God Roll), +Skill Gem, DPS, Spell Suppression.
    - Tính toán Open Suffix / Open Prefix.
    - Bùa ngọc, Trang sức, Bình Flasks.
    """

    @classmethod
    def detect_category(cls, item_class: str) -> ItemCategory:
        """Xác định ItemCategory từ chuỗi Item Class."""
        c = (item_class or "").lower()
        if "waystone" in c or "map" in c:
            return ItemCategory.WAYSTONE
        if any(w in c for w in [
            "bow", "crossbow", "claw", "dagger", "sword", "axe", "mace",
            "sceptre", "staff", "staves", "quarterstaff", "quarterstaves",
            "wand", "weapon", "spear", "flail"
        ]):
            return ItemCategory.WEAPON
        if "body" in c or "chest" in c or "armour" in c and "boots" not in c and "gloves" not in c and "helmet" not in c:
            return ItemCategory.BODY_ARMOUR
        if "helmet" in c:
            return ItemCategory.HELMET
        if "boot" in c or "shoe" in c:
            return ItemCategory.BOOTS
        if "glove" in c or "gauntlet" in c:
            return ItemCategory.GLOVES
        if "shield" in c or "focus" in c or "buckler" in c:
            return ItemCategory.SHIELD
        if "quiver" in c:
            return ItemCategory.QUIVER
        if "ring" in c:
            return ItemCategory.RING
        if "amulet" in c:
            return ItemCategory.AMULET
        if "belt" in c:
            return ItemCategory.BELT
        if "jewel" in c:
            return ItemCategory.JEWEL
        if "charm" in c:
            return ItemCategory.CHARM
        if "flask" in c:
            return ItemCategory.FLASK
        if "currency" in c:
            return ItemCategory.CURRENCY
        return ItemCategory.OTHER

    @classmethod
    def parse_rarity(cls, rarity_str: str) -> ItemRarity:
        r = (rarity_str or "").strip().upper()
        if r == "MAGIC":
            return ItemRarity.MAGIC
        if r == "RARE":
            return ItemRarity.RARE
        if r == "UNIQUE":
            return ItemRarity.UNIQUE
        return ItemRarity.NORMAL

    @classmethod
    def inspect(cls, raw_text: str) -> Optional[ItemInspectionReport]:
        """Phân tích và đánh giá chuyên sâu vật phẩm từ raw text clipboard."""
        parsed = UniversalItemParser.parse(raw_text)
        if not parsed:
            return None

        category = cls.detect_category(parsed.item_class)
        rarity = cls.parse_rarity(parsed.rarity)

        report = ItemInspectionReport(
            item_name=parsed.name or parsed.base_type,
            item_class=parsed.item_class,
            base_type=parsed.base_type,
            category=category,
            rarity=rarity,
            item_level=parsed.item_level,
            quality=parsed.quality,
            safety_score=100,
            quality_score=0,
        )

        # 1. Đánh giá chuyên biệt cho WAYSTONE (Bản đồ)
        if category == ItemCategory.WAYSTONE:
            cls._evaluate_waystone(parsed, report, raw_text)
            return report

        # 2. Đếm số lượng Prefix và Suffix hiện có
        prefix_count = 0
        suffix_count = 0

        for line, affix_type, tier, mod_name in parsed.explicit_lines:
            if affix_type == AffixType.PREFIX:
                prefix_count += 1
            elif affix_type == AffixType.SUFFIX:
                suffix_count += 1

        # Tính toán Open Affixes theo quy chuẩn POE2
        if rarity == ItemRarity.RARE:
            report.max_prefixes = 3
            report.max_suffixes = 3
            report.open_prefixes = max(0, 3 - prefix_count)
            report.open_suffixes = max(0, 3 - suffix_count)
        elif rarity == ItemRarity.MAGIC:
            report.max_prefixes = 1
            report.max_suffixes = 1
            report.open_prefixes = max(0, 1 - prefix_count)
            report.open_suffixes = max(0, 1 - suffix_count)
        else:
            report.max_prefixes = 0
            report.max_suffixes = 0
            report.open_prefixes = 0
            report.open_suffixes = 0

        # 3. Đánh giá các dòng Explicit Mod & Implicit Mod
        order_idx = 0
        lines_to_eval = parsed.ordered_lines if parsed.ordered_lines else parsed.explicit_lines
        for line, affix_type, tier, mod_name in lines_to_eval:
            mod_item = cls._evaluate_mod_line(line, category, affix_type, tier, mod_name)
            mod_item.original_order = order_idx
            report.ordered_modifiers.append(mod_item)
            report.raw_mods.append(mod_item)

            if mod_item.severity in [InspectionSeverity.REWARD, InspectionSeverity.GOD_ROLL]:
                report.green_mods.append(mod_item.text)
                if mod_item.severity == InspectionSeverity.GOD_ROLL:
                    report.quality_score += 35
                else:
                    report.quality_score += 20
            elif mod_item.severity in [InspectionSeverity.BRICK, InspectionSeverity.DANGEROUS]:
                report.red_mods.append(mod_item.text)
                report.quality_score -= 20
                report.safety_score -= 30
            elif mod_item.severity == InspectionSeverity.CRAFTING:
                report.yellow_mods.append(mod_item.text)
                report.quality_score += 10
            else:
                report.neutral_mods.append(mod_item.text)
                report.quality_score += 5
            order_idx += 1

        # 4. Cảnh báo tiềm năng chế đồ (Crafting / Open Affix)
        if rarity in [ItemRarity.RARE, ItemRarity.MAGIC]:
            if report.open_suffixes > 0:
                craft_msg = f"[CRAFT] Còn {report.open_suffixes} Open Suffix để đập Kháng/Rune"
                report.yellow_mods.append(craft_msg)
                report.quality_score += 10 * report.open_suffixes
            if report.open_prefixes > 0:
                craft_msg = f"[CRAFT] Còn {report.open_prefixes} Open Prefix để đập Máu/Damage"
                report.yellow_mods.append(craft_msg)
                report.quality_score += 10 * report.open_prefixes

        # Giới hạn quality_score trong khoảng [0, 150]
        report.quality_score = max(0, min(150, report.quality_score))
        report.safety_score = max(0, min(100, report.safety_score))

        # 5. Tổng kết nhận định (Summary)
        has_god_roll = any(m.severity == InspectionSeverity.GOD_ROLL for m in report.raw_mods)
        if has_god_roll or report.quality_score >= 80:
            report.summary = (
                f"⭐ GOD ROLL ({report.quality_score}đ) - {len(report.green_mods)} mod xịn, "
                f"{report.open_prefixes}P/{report.open_suffixes}S open"
            )
        elif report.quality_score >= 50:
            report.summary = (
                f"🟢 TRANG BỊ XỊN ({report.quality_score}đ) - {len(report.green_mods)} mod tốt, "
                f"{report.open_prefixes}P/{report.open_suffixes}S open"
            )
        elif report.yellow_mods:
            report.summary = (
                f"🟡 TIỀM NĂNG CHẾ ĐỒ ({report.quality_score}đ) - {report.open_prefixes}P/{report.open_suffixes}S open craft"
            )
        else:
            report.summary = f"⚪ BÌNH THƯỜNG ({report.quality_score}đ)"

        return report

    @classmethod
    def _evaluate_waystone(cls, parsed: ParsedItemData, report: ItemInspectionReport, raw_text: str) -> None:
        """Đánh giá bản đồ Waystone thông qua ModifierFilter và bảo toàn ordered_modifiers."""
        mod_rep = ModifierFilter.evaluate_modifiers(raw_text)
        report.is_brick = mod_rep.is_brick
        report.safety_score = mod_rep.safety_score

        order_idx = 0
        lines_to_eval = parsed.ordered_lines if parsed.ordered_lines else [
            (ln, AffixType.UNKNOWN, None, "") for ln in parsed.implicit_lines + [el[0] for el in parsed.explicit_lines]
        ]

        for line, affix_type, tier, mod_name in lines_to_eval:
            clean_for_match = re.sub(r"\([^)]*\)", "", line).strip()
            clean_for_match = re.sub(r"\s+", " ", clean_for_match)

            matched_red = False
            for pattern, cat, sev, desc in ModifierFilter.RED_PATTERNS:
                if re.search(pattern, clean_for_match, re.I):
                    sev_insp = InspectionSeverity.BRICK if sev == ModSeverity.BRICK else InspectionSeverity.DANGEROUS
                    mod_item = InspectionMod(
                        text=line,
                        affix_type=affix_type or AffixType.UNKNOWN,
                        severity=sev_insp,
                        category=cat,
                        description=desc,
                        tier=tier,
                        color_code="#FF4D4D",
                        original_order=order_idx,
                    )
                    report.ordered_modifiers.append(mod_item)
                    report.raw_mods.append(mod_item)
                    report.red_mods.append(line)
                    if sev_insp == InspectionSeverity.BRICK:
                        report.is_brick = True
                    matched_red = True
                    break

            if matched_red:
                order_idx += 1
                continue

            matched_green = False
            for pattern, cat, sev, desc in ModifierFilter.GREEN_PATTERNS:
                if re.search(pattern, clean_for_match, re.I):
                    mod_item = InspectionMod(
                        text=line,
                        affix_type=affix_type or AffixType.UNKNOWN,
                        severity=InspectionSeverity.REWARD,
                        category=cat,
                        description=desc,
                        tier=tier,
                        color_code="#2ECC71",
                        original_order=order_idx,
                    )
                    report.ordered_modifiers.append(mod_item)
                    report.raw_mods.append(mod_item)
                    report.green_mods.append(line)
                    matched_green = True
                    break

            if matched_green:
                order_idx += 1
                continue

            mod_item = InspectionMod(
                text=line,
                affix_type=affix_type or AffixType.UNKNOWN,
                severity=InspectionSeverity.NEUTRAL,
                category="General",
                description="",
                tier=tier,
                color_code="#8888FF",
                original_order=order_idx,
            )
            report.ordered_modifiers.append(mod_item)
            report.raw_mods.append(mod_item)
            report.neutral_mods.append(line)
            order_idx += 1

        # Tính quality_score cho Waystone dựa trên số lượng mod thưởng
        report.quality_score = len(report.green_mods) * 30

        if report.is_brick:
            report.summary = f"🛑 BRICK WAYSTONE: CẤM CHẠY (Safety: {report.safety_score}%)"
        elif report.safety_score < 70:
            report.summary = f"⚠️ CẢNH BÁO WAYSTONE: NGUY HIỂM CAO (Safety: {report.safety_score}%)"
        elif report.green_mods:
            report.summary = f"🟢 WAYSTONE AN TOÀN & THƯỞNG CAO (Safety: {report.safety_score}%, {len(report.green_mods)} Reward Mod)"
        else:
            report.summary = f"🟢 WAYSTONE AN TOÀN (Safety: {report.safety_score}%)"

    @classmethod
    def _evaluate_mod_line(
        cls,
        line: str,
        category: ItemCategory,
        affix_type: Optional[AffixType],
        tier: Optional[int],
        mod_name: str,
    ) -> InspectionMod:
        """Đánh giá chi tiết từng dòng thuộc tính dựa trên Category và giá trị số, bảo toàn text nguyên bản."""
        affix = affix_type or AffixType.UNKNOWN

        # 1. MÁU (Life)
        m_life = re.search(r"\+(\d+)\s+to\s+maximum\s+Life", line, re.I)
        if m_life:
            val = int(m_life.group(1))
            # Trang sức (Ring, Amulet) có pool Máu tối đa thấp hơn áo giáp (T1 ~70-80)
            is_jewelry = category in [ItemCategory.RING, ItemCategory.AMULET]
            min_god = 75 if is_jewelry else 110
            min_reward = 60 if is_jewelry else 80

            if val >= min_god:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.GOD_ROLL,
                    category="Life",
                    description="Máu T1 tối đa cực cao",
                    tier=tier or 1,
                    color_code="#2ECC71",
                )
            elif val >= min_reward:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Life",
                    description="Lượng Máu cộng thêm tốt",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 2. KHÁNG (Resistances)
        # Đơn kháng (Fire, Cold, Lightning)
        m_single_res = re.search(r"\+(\d+)%\s+to\s+(Fire|Cold|Lightning)\s+Resistance", line, re.I)
        if m_single_res:
            val, elem = int(m_single_res.group(1)), m_single_res.group(2)
            if val >= 35:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Resistance",
                    description=f"Kháng nguyên tố {elem} cao",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # All Elemental Res hoặc Chaos Res
        m_all_or_chaos_res = re.search(
            r"\+(\d+)%\s+to\s+(all\s+Elemental|Chaos)\s+Resistances?", line, re.I
        )
        if m_all_or_chaos_res:
            val, r_type = int(m_all_or_chaos_res.group(1)), m_all_or_chaos_res.group(2)
            if val >= 20:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Resistance",
                    description=f"Kháng toàn diện / Chaos giá trị cao",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 3. TỐC CHẠY TRÊN GIÀY (Movement Speed)
        m_ms = re.search(r"(\d+)%\s+increased\s+Movement\s+Speed", line, re.I)
        if m_ms:
            val = int(m_ms.group(1))
            if val >= 30:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.GOD_ROLL,
                    category="Movement Speed",
                    description="Tốc chạy tối đa (God Roll)",
                    tier=tier or 1,
                    color_code="#2ECC71",
                )
            elif val >= 25:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Movement Speed",
                    description="Tốc chạy cao",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 4. +SKILL GEM
        m_gem = re.search(
            r"\+(\d+)\s+to\s+Level\s+of\s+(?:all\s+)?(?:\w+\s+)?(?:Skill\s+)?Gems",
            line,
            re.I,
        )
        if m_gem:
            val = int(m_gem.group(1))
            if val >= 1:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.GOD_ROLL,
                    category="Skill Gems",
                    description="Tăng cấp độ Gem kỹ năng cực kỳ giá trị",
                    tier=tier or 1,
                    color_code="#2ECC71",
                )

        # 5. SPELL SUPPRESSION
        m_suppress = re.search(r"\+?(\d+)%\s+chance\s+to\s+Suppress\s+Spell\s+Damage", line, re.I)
        if m_suppress:
            val = int(m_suppress.group(1))
            if val >= 12:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Spell Suppression",
                    description="Kháng giảm sát thương phép cao",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 6. SÁT THƯƠNG VŨ KHÍ (WEAPON)
        if category == ItemCategory.WEAPON:
            m_inc_phys = re.search(r"(\d+)%\s+increased\s+Physical\s+Damage", line, re.I)
            if m_inc_phys and int(m_inc_phys.group(1)) >= 80:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Weapon Damage",
                    description="Tăng mạnh % sát thương vật lý",
                    tier=tier,
                    color_code="#2ECC71",
                )
            m_add_dmg = re.search(r"Adds\s+(\d+)\s+to\s+(\d+)\s+(?:Physical|Fire|Cold|Lightning|Chaos)\s+Damage", line, re.I)
            if m_add_dmg and (int(m_add_dmg.group(1)) + int(m_add_dmg.group(2))) / 2.0 >= 25.0:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Weapon Damage",
                    description="Sát thương cơ bản cộng thêm cao",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 7. TRANG SỨC (RING, AMULET, BELT) & BÙA NGỌC (JEWEL, CHARM)
        if category in [ItemCategory.RING, ItemCategory.AMULET, ItemCategory.BELT, ItemCategory.JEWEL, ItemCategory.CHARM]:
            # Critical Strike Multiplier
            m_crit_multi = re.search(r"\+(\d+)%\s+to\s+(?:Global\s+)?Critical\s+Strike\s+Multiplier", line, re.I)
            if m_crit_multi and int(m_crit_multi.group(1)) >= 20:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Critical",
                    description="Sát thương chí mạng cao",
                    tier=tier,
                    color_code="#2ECC71",
                )
            # % Sát thương nguyên tố
            m_ele_dmg = re.search(r"(\d+)%\s+increased\s+Elemental\s+Damage", line, re.I)
            if m_ele_dmg and int(m_ele_dmg.group(1)) >= 20:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Elemental Damage",
                    description="Tăng sát thương nguyên tố",
                    tier=tier,
                    color_code="#2ECC71",
                )
            # % Máu hoặc % ES trên Ngọc / Jewel
            m_pct_life = re.search(r"(\d+)%\s+increased\s+maximum\s+Life", line, re.I)
            if m_pct_life and int(m_pct_life.group(1)) >= 5:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Life %",
                    description="Gia tăng % Máu tối đa",
                    tier=tier,
                    color_code="#2ECC71",
                )
            m_pct_es = re.search(r"(\d+)%\s+increased\s+maximum\s+Energy\s+Shield", line, re.I)
            if m_pct_es and int(m_pct_es.group(1)) >= 6:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Energy Shield %",
                    description="Gia tăng % Energy Shield",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # 8. BÌNH FLASK (FLASK)
        if category == ItemCategory.FLASK:
            m_imm = re.search(r"Immunity\s+to\s+(Bleeding|Shock|Freeze|Poison|Ignite)", line, re.I)
            if m_imm:
                ailment = m_imm.group(1)
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Flask Immunity",
                    description=f"Miễn nhiễm hiệu ứng bất lợi {ailment}",
                    tier=tier,
                    color_code="#2ECC71",
                )
            m_rec = re.search(r"(\d+)%\s+increased\s+(?:Amount\s+Recovered|Recovery\s+Rate)", line, re.I)
            if m_rec and int(m_rec.group(1)) >= 20:
                return InspectionMod(
                    text=line,
                    affix_type=affix,
                    severity=InspectionSeverity.REWARD,
                    category="Flask Recovery",
                    description="Tăng tốc độ hoặc lượng hồi phục",
                    tier=tier,
                    color_code="#2ECC71",
                )

        # Thuộc tính trung tính mặc định
        return InspectionMod(
            text=line,
            affix_type=affix,
            severity=InspectionSeverity.NEUTRAL,
            category="General",
            description="",
            tier=tier,
            color_code="#8888FF",
        )


def inspect_item(raw_text: str) -> Optional[ItemInspectionReport]:
    """Hàm tiện ích cấp module phân tích và đánh giá vật phẩm."""
    return UniversalItemInspector.inspect(raw_text)
