"""
AutoPOE2 Pickit Filter Compiler (Phase P2 - Doc 29 mục 9.6)
Biên dịch các quy tắc .ipd từ Python thành tệp pickup_filter.json nhỏ gọn
cho C++ Core nạp và lọc đồ tức thì ở tần số 120Hz mà không cần phân tích chuỗi.
"""

from __future__ import annotations
import os
import json
import configparser
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, List, Set

from .parser import parse_ipd, Clause, BinaryOp, PickitRule


def compile_filter(ipd_path: Path, output_paths: List[Path]) -> Dict[str, Any]:
    """
    Đọc file .ipd, phân tích pre-conditions của các enabled rules và tạo cấu trúc JSON
    cho Core 120Hz.
    """
    if not ipd_path.is_file():
        raise FileNotFoundError(f"Không tìm thấy file kịch bản Pickit: {ipd_path}")

    content = ipd_path.read_text(encoding="utf-8")
    rules = parse_ipd(content)

    exact_types: Set[str] = set()
    name_substrings: Set[str] = {
        # Baseline an toàn cho POE2: Vàng và các loại tiền tệ / vật phẩm Endgame cốt lõi
        "gold", "orb", "mirror", "divine", "exalt", "chaos", "vaal",
        "waystone", "tablet", "essence", "splinter", "catalyst",
        "distillation", "omen", "gemcutter", "jeweller", "annul",
    }
    reject_name_substrings: Set[str] = {
        # Các vật phẩm rác / cuộn giấy mặc định ẩn
        "scroll of wisdom", "portal scroll", "iron ring", "rustic sash",
        "crude bow", "crude staff", "driftwood wand", "torn boots",
    }
    pickup_all_above_rarity = -1

    rarity_map = {
        "normal": 0, "white": 0,
        "magic": 1, "blue": 1,
        "rare": 2, "yellow": 2,
        "unique": 3, "orange": 3,
    }

    for rule in rules:
        if not rule.enabled:
            continue

        # Duyệt cây AST phần PRE để trích xuất điều kiện
        stack = [rule.pre_ast]
        while stack:
            curr = stack.pop()
            if curr is None:
                continue
            if isinstance(curr, BinaryOp):
                stack.append(curr.left)
                stack.append(curr.right)
            elif isinstance(curr, Clause):
                k = curr.key.lower()
                v = curr.value.strip()

                if k in ("type", "name") and curr.op == "==":
                    exact_types.add(v)
                    # Nếu tên chứa chữ đặc biệt thì thêm vào substring
                    name_substrings.add(v.lower())
                elif k == "rarity":
                    val_num = rarity_map.get(v.lower())
                    if val_num is not None:
                        if curr.op in (">=", "=="):
                            if pickup_all_above_rarity == -1 or val_num < pickup_all_above_rarity:
                                pickup_all_above_rarity = val_num
                        elif curr.op == ">":
                            target_r = val_num + 1
                            if pickup_all_above_rarity == -1 or target_r < pickup_all_above_rarity:
                                pickup_all_above_rarity = target_r
                elif k == "category":
                    cat_name = v.lower()
                    if cat_name in ("waystone", "tablet", "flask", "charm", "gem"):
                        name_substrings.add(cat_name)

    # Mặc định nếu không có rule rarity rõ ràng, nhặt tất cả Unique (rarity >= 3)
    if pickup_all_above_rarity == -1:
        pickup_all_above_rarity = 3

    result = {
        "schema": "autopoE2.pickup_filter.v1",
        "generated_at": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
        "source_ipd": str(ipd_path.name),
        "pickup_all_above_rarity": pickup_all_above_rarity,
        "name_substrings": sorted(list(name_substrings)),
        "exact_types": sorted(list(exact_types)),
        "reject_name_substrings": sorted(list(reject_name_substrings)),
    }

    json_str = json.dumps(result, indent=2, ensure_ascii=False)

    for out_path in output_paths:
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_text(json_str, encoding="utf-8")

    return result


def main():
    root = Path(__file__).resolve().parent.parent.parent.parent
    ini_path = root / "data" / "pickit" / "pickit.ini"

    profile_name = "default"
    if ini_path.is_file():
        cfg = configparser.ConfigParser()
        cfg.read(ini_path, encoding="utf-8")
        profile_name = cfg.get("pickit", "active_profile", fallback="default")

    ipd_path = root / "data" / "pickit" / f"{profile_name}.ipd"
    out_release = root / "bin" / "Release" / "pickup_filter.json"
    out_data = root / "data" / "pickup_filter.json"

    print(f"[PickitCompiler] Compiling profile '{profile_name}': {ipd_path}")
    res = compile_filter(ipd_path, [out_release, out_data])
    print(f"[PickitCompiler] >> Success! Exported {len(res['name_substrings'])} substrings, "
          f"{len(res['exact_types'])} exact types, {len(res['reject_name_substrings'])} reject substrings.")


if __name__ == "__main__":
    main()
