"""
tests/test_fashion_rules_batch.py
Batch-test 100 SP ngẫu nhiên → kiểm tra fashion rule coverage & integrity.

Run:
    cd backend
    $env:PYTHONIOENCODING="utf-8"
    .venv\Scripts\python.exe tests/test_fashion_rules_batch.py --limit 100
"""

import sys
import os
import random
import argparse
from collections import defaultdict

# ── path ──────────────────────────────────────────────────────────────────────
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from worker.stylist_engine import StylistEngine
from common.pool_wrapper import get_pooled_connection_compat


def fetch_all_anchor_categories():
    """Lấy tập hợp (anchor_category, gender_target) đã có rules trong DB."""
    conn = None
    try:
        conn = get_pooled_connection_compat()
        cur = conn.cursor()
        cur.execute("""\
            SELECT DISTINCT anchor_category, gender_target
            FROM dashboard_canifa.chatbot_fashion_rules
            WHERE gender_target != 'all'
        """)
        rows = cur.fetchall()
        cur.close()
        return {(r[0].strip().lower(), r[1].strip().lower()) for r in rows}
    except Exception as e:
        print(f"[DB ERROR] {e}")
        return set()
    finally:
        if conn:
            conn.close()


def run_batch_test(limit: int = 100, verbose: bool = False):
    engine = StylistEngine()
    catalog = engine._load_catalog()

    if not catalog:
        print("Catalog rong!")
        return

    print(f"Tong so SP trong catalog: {len(catalog)}")

    # Chỉ lấy SP có product_line + gender
    valid = [p for p in catalog if p.get("product_line") and p.get("gender")]
    samples = random.sample(valid, min(limit, len(valid)))

    print(f"Test {len(samples)} SP ngau nhien...\n")

    # Anchor categories có rules trong DB (lowercase)
    db_anchors = fetch_all_anchor_categories()

    stats = {
        "total": len(samples),
        "passed": 0,
        "no_rules_in_db": 0,
        "empty_all_occasions": 0,
        "rule_violations": 0,
    }

    # Thống kê anchor nào không có rules
    missing_anchors: dict[str, list[str]] = defaultdict(list)
    violation_details: list[str] = []
    empty_details: list[str] = []

    for p in samples:
        code = p.get("code", "?")
        anchor_cat = p.get("product_line", "")
        gender_raw = p.get("gender", "")
        gender_norm = engine._normalize_gender(gender_raw)

        # Kiểm tra xem DB có rules cho combo này không
        anchor_lower = anchor_cat.strip().lower()
        has_specific = (anchor_lower, gender_norm) in db_anchors
        has_all = (anchor_lower, "all") in db_anchors
        if not has_specific and not has_all:
            stats["no_rules_in_db"] += 1
            missing_anchors[f"{anchor_cat} [{gender_raw}→{gender_norm}]"].append(code)
            continue

        # Gọi engine
        ai_matches = engine.compute_dynamic_rule_matches(code)
        db_rules = engine._fetch_rules_with_reason(anchor_cat, gender_raw)

        # allowed = {occ: set(target_cat_lower)}
        allowed_by_occ: dict[str, set] = defaultdict(set)
        for r in db_rules:
            allowed_by_occ[r["occ"]].add(r["target_cat"].strip().lower())

        is_all_empty = True
        violations = []

        for occ, allowed_targets in allowed_by_occ.items():
            occ_data = ai_matches.get(occ, {})
            if not occ_data:
                continue
            is_all_empty = False
            for role, items in occ_data.items():
                for item in items:
                    item_cat = item.get("product_line", "").strip().lower()
                    if item_cat not in allowed_targets:
                        violations.append(
                            f"  Dip [{occ}] role={role}: recommend '{item_cat}' | Cho phep: {allowed_targets}"
                        )

        if is_all_empty:
            stats["empty_all_occasions"] += 1
            empty_details.append(f"  {anchor_cat} [{gender_norm}] ({code}) -> Toan bo dip TRONG (mau khong khop)")

        if violations:
            stats["rule_violations"] += 1
            violation_details.append(f"  {anchor_cat} [{gender_norm}] ({code}):")
            violation_details.extend(violations)
        else:
            if not is_all_empty:
                stats["passed"] += 1

    # ── REPORT ──────────────────────────────────────────────────────────────
    sep = "=" * 55
    print(sep)
    print("  KET QUA KIEM THU FASHION RULES")
    print(sep)
    print(f"Tong test           : {stats['total']}")
    print(f"Passed (ok)         : {stats['passed']}")
    print(f"Khong co rules DB   : {stats['no_rules_in_db']}  <- can seed them")
    print(f"Rules co, nhung trong: {stats['empty_all_occasions']}  <- catalog mau chua du")
    print(f"Vi pham rules       : {stats['rule_violations']}  <- loi engine")
    print()

    # Thống kê anchor thiếu rules
    if missing_anchors:
        print(f"--- ANCHOR CATEGORY CHUA SEED RULES ({len(missing_anchors)} loai) ---")
        sorted_missing = sorted(missing_anchors.items(), key=lambda x: -len(x[1]))
        for anchor, codes in sorted_missing[:20]:
            print(f"  {len(codes):3d} SP  |  {anchor}")
        if len(sorted_missing) > 20:
            print(f"  ... va {len(sorted_missing) - 20} loai khac")
        print()

    if violation_details:
        print(f"--- VI PHAM RULES ({stats['rule_violations']} SP) ---")
        for line in violation_details[:30]:
            print(line)
        print()

    if verbose and empty_details:
        print("--- RONG DO MAU (verbose) ---")
        for line in empty_details[:20]:
            print(line)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--limit", type=int, default=100)
    parser.add_argument("--verbose", action="store_true")
    args = parser.parse_args()
    run_batch_test(args.limit, args.verbose)
