"""AutoPOE2 - Advanced Item Tooltip Tier & Mod Evaluator (Doc 29 / Doc 68).
=============================================================================
Động cơ thẩm định trang bị và vật phẩm dựa trên phân tích Tooltip (OCR & Text):
- Tiếp nhận ảnh chụp Tooltip trang bị hiếm thật từ thực địa (captures/*.png) hoặc text.
- Nhận diện các dòng thuộc tính giá trị cao (Tier 1 Life/ES, +Skill Gems, High Elemental Resistances, Critical Multiplier, High Physical/Elemental DPS).
- Tính toán điểm số hiệp đồng thuộc tính (Stat Synergy Score) và Pseudo Resistances.
- Xuất đánh giá phân loại quyết định:
  + KEEP: Giữ lại trên người / Món đồ giá trị cực cao (God Roll / 3+ T1 / +Gems).
  + STASH: Cất vào Hòm đồ để trao đổi hoặc chế đồ (2+ T1/T2, đồ có giá trị giao dịch).
  + VENDOR: Bán cho NPC lấy vàng / đồ rác thuộc tính thấp hoặc không có hiệp đồng.

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

from __future__ import annotations

from dataclasses import dataclass, field
import os
import re
from typing import Any, Dict, List, Optional, Tuple, Union

import numpy as np

try:
    from PIL import Image
except ImportError:
    Image = None  # type: ignore[assignment]

try:
    import winocr
except ImportError:
    winocr = None

from src.assistant_tool.pickit.mod_tier_patterns import (
    EvaluatedMod,
    ItemEvaluationAction,
    ModCategory,
    classify_single_mod_line,
)


@dataclass
class ItemEvaluationReport:
    """Báo cáo đánh giá toàn diện giá trị và phân loại vật phẩm."""
    item_name: str = ""
    item_class: str = ""
    rarity: str = "NORMAL"
    item_level: int = 0
    action: ItemEvaluationAction = ItemEvaluationAction.VENDOR
    total_score: float = 0.0
    tier_1_count: int = 0
    tier_2_count: int = 0
    high_value_mods: List[EvaluatedMod] = field(default_factory=list)
    all_mods: List[EvaluatedMod] = field(default_factory=list)
    reasons: List[str] = field(default_factory=list)
    pseudo_resists: Dict[str, float] = field(default_factory=dict)
    synergy_bonuses: List[str] = field(default_factory=list)
    raw_text: str = ""


class ItemTooltipEvaluator:
    """Động cơ bóc tách và định giá Tooltip trang bị theo chuẩn Tier & Mod POE2."""

    # Ngưỡng phân loại hành động
    KEEP_SCORE_THRESHOLD: float = 70.0
    STASH_SCORE_THRESHOLD: float = 40.0

    def __init__(
        self,
        keep_score_threshold: float = 70.0,
        stash_score_threshold: float = 40.0,
    ) -> None:
        """Khởi tạo ItemTooltipEvaluator.

        Args:
            keep_score_threshold: Ngưỡng điểm tối thiểu để phân loại KEEP.
            stash_score_threshold: Ngưỡng điểm tối thiểu để phân loại STASH.
        """
        self.keep_score_threshold = keep_score_threshold
        self.stash_score_threshold = stash_score_threshold

    def evaluate_text(self, text_blob: str) -> ItemEvaluationReport:
        """Đánh giá vật phẩm từ chuỗi văn bản Tooltip (Clipboard hoặc OCR).

        Args:
            text_blob: Chuỗi văn bản đầy đủ của tooltip vật phẩm.

        Returns:
            ItemEvaluationReport chứa kết quả phân loại và chi tiết mod.
        """
        if not text_blob or not text_blob.strip():
            return ItemEvaluationReport(action=ItemEvaluationAction.VENDOR, reasons=["Empty tooltip text"])

        lines = [line.strip() for line in text_blob.strip().splitlines() if line.strip()]

        # 1. Trích xuất thông tin Header
        item_class = ""
        rarity = "NORMAL"
        item_name = ""
        item_level = 0

        header_lines_processed = 0
        for i, line in enumerate(lines):
            if line.startswith("Item Class:"):
                item_class = line.split(":", 1)[1].strip()
                header_lines_processed = max(header_lines_processed, i + 1)
            elif line.startswith("Rarity:"):
                rarity = line.split(":", 1)[1].strip().upper()
                if i + 1 < len(lines) and not lines[i + 1].startswith("---"):
                    item_name = lines[i + 1].strip()
                header_lines_processed = max(header_lines_processed, i + 2)
            elif line.startswith("Item Level:"):
                m = re.search(r"Item\s+Level:\s*(\d+)", line, re.IGNORECASE)
                if m:
                    item_level = int(m.group(1))

        # Fallback tìm item level nếu text OCR dạng iLvI: 80 hoặc iLvl: 80
        if item_level == 0:
            m_ilvl = re.search(r"iLv[lI]:?\s*(\d+)", text_blob, re.IGNORECASE)
            if m_ilvl:
                item_level = int(m_ilvl.group(1))

        # 2. Bóc tách và phân loại các dòng mod
        evaluated_mods: List[EvaluatedMod] = []
        skip_prefixes = (
            "--------", "Item Class", "Rarity", "Requirements", "Level:", "Str:", "Dex:", "Int:",
            "Sockets:", "Item Level:", "Corrupted", "Can be used in a Map Device"
        )

        for line in lines:
            # Loại bỏ các tag phân loại advance modifier dạng { Prefix Modifier ... }
            clean_line = re.sub(r"\{[^}]*\}", "", line).strip()
            # Loại bỏ icon bullet rác nếu OCR nhận nhầm
            clean_line = clean_line.lstrip("•-* ")
            if not clean_line:
                continue

            if any(clean_line.startswith(p) for p in skip_prefixes):
                continue
            if clean_line == item_name:
                continue

            mod_eval = classify_single_mod_line(clean_line)
            if mod_eval is not None:
                evaluated_mods.append(mod_eval)

        # 3. Tính toán Pseudo Resistances & Thống kê
        fire_res = 0.0
        cold_res = 0.0
        light_res = 0.0
        chaos_res = 0.0
        total_ele_res = 0.0
        has_skill_gems = False
        max_life_val = 0.0
        has_move_speed_t1 = False

        tier_1_count = 0
        tier_2_count = 0
        base_score = 0.0
        high_value_mods: List[EvaluatedMod] = []

        for m_eval in evaluated_mods:
            base_score += m_eval.score
            if m_eval.is_tier_1:
                tier_1_count += 1
                high_value_mods.append(m_eval)
            elif m_eval.tier_estimate == 2:
                tier_2_count += 1
                high_value_mods.append(m_eval)

            # Thu thập chỉ số thống kê
            if m_eval.category == ModCategory.RESISTANCE:
                if "Fire" in m_eval.name:
                    fire_res += m_eval.value
                elif "Cold" in m_eval.name:
                    cold_res += m_eval.value
                elif "Lightning" in m_eval.name:
                    light_res += m_eval.value
                elif "Chaos" in m_eval.name:
                    chaos_res += m_eval.value
                elif "All Elemental" in m_eval.name:
                    total_ele_res += m_eval.value
            elif m_eval.category == ModCategory.SKILL_GEMS:
                has_skill_gems = True
            elif m_eval.category == ModCategory.LIFE:
                max_life_val = max(max_life_val, m_eval.value)
            elif m_eval.category == ModCategory.MOVE_SPEED and m_eval.is_tier_1:
                has_move_speed_t1 = True

        total_ele_res += (fire_res + cold_res + light_res)
        pseudo_res = {
            "fire": fire_res,
            "cold": cold_res,
            "lightning": light_res,
            "chaos": chaos_res,
            "total_ele": total_ele_res,
            "total_all": total_ele_res + chaos_res,
        }

        # 4. Hiệp đồng thuộc tính (Stat Synergy Bonuses)
        synergy_bonuses: List[str] = []
        synergy_score = 0.0

        # Hiệp đồng 1: Máu cao + Đa Kháng
        if max_life_val >= 70.0 and total_ele_res >= 60.0:
            synergy_score += 20.0
            synergy_bonuses.append("Life + Multi Resistance Synergy (+20 pts)")

        # Hiệp đồng 2: Ba dòng Kháng Nguyên Tố cực cao
        if total_ele_res >= 80.0:
            synergy_score += 15.0
            synergy_bonuses.append(f"High Pseudo Elemental Resistance ({int(total_ele_res)}%) (+15 pts)")

        # Hiệp đồng 3: +Skill Gems kết hợp
        if has_skill_gems:
            synergy_score += 20.0
            synergy_bonuses.append("High-Value +Skill Gems Anchor (+20 pts)")

        # Hiệp đồng 4: Giày Tốc Độ Chạy + Máu / Kháng
        if has_move_speed_t1 and (max_life_val >= 50.0 or total_ele_res >= 30.0):
            synergy_score += 20.0
            synergy_bonuses.append("Boots Movement Speed + Survival Synergy (+20 pts)")

        # Hiệp đồng 5: Kháng Hỗn Loạn cao kết hợp Kháng Nguyên Tố
        if chaos_res >= 20.0 and total_ele_res >= 40.0:
            synergy_score += 15.0
            synergy_bonuses.append("Chaos & Elemental Survival Synergy (+15 pts)")

        total_score = max(0.0, base_score + synergy_score)

        # 5. Quyết định Phân Loại (KEEP / STASH / VENDOR)
        reasons: List[str] = []
        action = ItemEvaluationAction.VENDOR

        # Kiểm tra điều kiện KEEP (God Roll / 3+ T1 / +Gems)
        if (
            total_score >= self.keep_score_threshold
            or tier_1_count >= 3
            or (has_skill_gems and total_score >= 50.0)
            or (max_life_val >= 100.0 and total_ele_res >= 80.0)
            or (has_move_speed_t1 and max_life_val >= 80.0 and total_ele_res >= 60.0)
        ):
            action = ItemEvaluationAction.KEEP
            if tier_1_count >= 3:
                reasons.append(f"God-roll gear with {tier_1_count} Tier 1 affixes")
            if has_skill_gems:
                reasons.append("+Skill Gems with strong supporting stats")
            if total_score >= self.keep_score_threshold:
                reasons.append(f"Outstanding total score: {total_score:.1f}")

        # Kiểm tra điều kiện STASH (Đồ tốt bán sàn / 2 T1 / 1 T1 + T2)
        elif (
            total_score >= self.stash_score_threshold
            or tier_1_count >= 2
            or (tier_1_count >= 1 and tier_2_count >= 1)
            or (max_life_val >= 70.0 and total_ele_res >= 40.0)
            or (chaos_res >= 25.0)
            or has_move_speed_t1
        ):
            action = ItemEvaluationAction.STASH
            if tier_1_count >= 2:
                reasons.append(f"Tradeable gear with {tier_1_count} Tier 1 affixes")
            elif has_move_speed_t1:
                reasons.append("High tier Movement Speed boots")
            elif chaos_res >= 25.0:
                reasons.append(f"High Chaos Resistance ({int(chaos_res)}%)")
            else:
                reasons.append(f"Valuable stats total score: {total_score:.1f}")

        # Mặc định VENDOR
        else:
            action = ItemEvaluationAction.VENDOR
            reasons.append(f"Low utility or vendor filler (Score: {total_score:.1f}, T1: {tier_1_count})")

        return ItemEvaluationReport(
            item_name=item_name or "Unknown Item",
            item_class=item_class,
            rarity=rarity,
            item_level=item_level,
            action=action,
            total_score=total_score,
            tier_1_count=tier_1_count,
            tier_2_count=tier_2_count,
            high_value_mods=high_value_mods,
            all_mods=evaluated_mods,
            reasons=reasons,
            pseudo_resists=pseudo_res,
            synergy_bonuses=synergy_bonuses,
            raw_text=text_blob,
        )

    def evaluate_image(
        self,
        img_input: Union[str, Image.Image, np.ndarray],
    ) -> ItemEvaluationReport:
        """Đánh giá vật phẩm từ ảnh chụp Tooltip hoặc toàn màn hình thông qua OCR.

        Args:
            img_input: Đường dẫn ảnh, đối tượng PIL Image, hoặc numpy array.

        Returns:
            ItemEvaluationReport được bóc tách từ ảnh.
        """
        pil_img: Optional[Image.Image] = None
        if isinstance(img_input, str):
            if os.path.exists(img_input) and Image is not None:
                pil_img = Image.open(img_input).convert("RGB")
        elif isinstance(img_input, np.ndarray) and Image is not None:
            pil_img = Image.fromarray(img_input).convert("RGB")
        elif Image is not None and isinstance(img_input, Image.Image):
            pil_img = img_input.convert("RGB")

        if pil_img is None:
            return ItemEvaluationReport(action=ItemEvaluationAction.VENDOR, reasons=["Invalid image input"])

        # Sử dụng winocr trích xuất toàn bộ văn bản
        text_lines: List[str] = []
        if winocr is not None:
            try:
                ocr_result = winocr.recognize_pil_sync(pil_img)
                for line in ocr_result.get("lines", []):
                    txt = line.get("text", "").strip()
                    if txt:
                        text_lines.append(txt)
            except Exception as e:
                return ItemEvaluationReport(
                    action=ItemEvaluationAction.VENDOR,
                    reasons=[f"OCR recognition error: {e}"],
                )

        full_text = "\n".join(text_lines)
        return self.evaluate_text(full_text)
