"""Parse une matrice attaquant×receveur depuis un .xlsx vers JSON.

Lit `Elements_<Game>.xlsx` (placé à la racine du projet, à adapter selon le nom)
et produit `csv_data/<game>/element_relations.json` :

    [
      {"attacker": "Feu", "defender": "Plante", "multiplier": 2.0},
      {"attacker": "Feu", "defender": "Eau",    "multiplier": 0.5},
      ...
    ]

Format Excel attendu :
- Ligne 1 : « Receveur → / Lanceur ↓ » en A1, puis noms des receveurs en B1..N1
- Lignes 2+ : nom de l'attaquant en colonne A, multiplicateurs en B..N
- Valeurs : `x0.5`, `x2`, `x0`, `x3`, `x1,5` (virgule FR acceptée)
- Cellule vide = neutre ×1 (non stocké)

Usage :
    py tools/parse_element_relations.py --game=narval-souls --file=Elements_Narval_Souls.xlsx
"""
import json
import sys
from pathlib import Path

import openpyxl

ROOT = Path(r"c:\wamp64\www\csi-world")

# Couleurs « theme » Office non résolvables fiablement → fallback hardcodé
# (cf. plan de feature : Terre/Acier/Ténèbres/Chaos pour le tableau NS).
THEME_FALLBACKS = {
    0: "#A8A8A8",  # gris métal (Acier)
    1: "#1A1A1A",  # noir profond (Ténèbres)
    4: "#7A1FA2",  # violet sombre (Chaos)
    5: "#964B00",  # marron (Terre)
}


def cell_color(cell) -> str | None:
    """Renvoie `#RRGGBB` depuis cell.fill.fgColor, ou None si indéterminable."""
    if cell.fill is None or cell.fill.fill_type != "solid" or cell.fill.fgColor is None:
        return None
    fg = cell.fill.fgColor
    if fg.type == "rgb" and isinstance(fg.rgb, str) and len(fg.rgb) == 8:
        # Format ARGB (FFRRGGBB) — on retire l'alpha.
        return "#" + fg.rgb[-6:].upper()
    if fg.type == "theme":
        return THEME_FALLBACKS.get(fg.theme)
    return None


def parse_multiplier(raw) -> float | None:
    """Convertit 'x0.5', 'x1,5', 'x0' → float. None si vide ou incohérent."""
    if raw is None:
        return None
    s = str(raw).strip()
    if not s:
        return None
    s = s.lower().lstrip("x").replace(",", ".")
    try:
        return float(s)
    except ValueError:
        return None


def process(game: str, src: Path) -> None:
    if not src.exists():
        print(f"[ERROR] introuvable : {src}", file=sys.stderr)
        sys.exit(1)

    wb = openpyxl.load_workbook(src, data_only=True)
    if len(wb.sheetnames) != 1:
        print(f"[WARN] {src.name} a {len(wb.sheetnames)} feuilles, utilisation de la première : {wb.sheetnames[0]}")
    ws = wb[wb.sheetnames[0]]

    # En-tête : col A1 = libellé, B1..N1 = receveurs
    header = list(ws[1])
    receivers = []
    colors = {}  # element name → "#RRGGBB"
    for cell in header[1:]:
        v = cell.value
        if v is None:
            break
        name = str(v).strip()
        receivers.append(name)
        c = cell_color(cell)
        if c is not None:
            colors[name] = c

    # Compléter via la colonne A (lignes 2+) au cas où des couleurs y soient
    # définies mais absentes de l'en-tête.
    for row in range(2, 2 + len(receivers)):
        cell = ws.cell(row=row, column=1)
        v = cell.value
        if v is None:
            continue
        name = str(v).strip()
        if name and name not in colors:
            c = cell_color(cell)
            if c is not None:
                colors[name] = c

    relations = []
    skipped   = 0
    for row in ws.iter_rows(min_row=2, values_only=True):
        attacker = row[0]
        if not attacker or not str(attacker).strip():
            continue
        attacker = str(attacker).strip()

        for i, raw in enumerate(row[1:1 + len(receivers)]):
            m = parse_multiplier(raw)
            if m is None:
                if raw is not None and str(raw).strip():
                    print(f"[WARN] valeur non parsable ({attacker} × {receivers[i]}) = {raw!r}", file=sys.stderr)
                    skipped += 1
                continue
            relations.append({
                "attacker":   attacker,
                "defender":   receivers[i],
                "multiplier": m,
            })

    dst_dir = ROOT / "csv_data" / game
    dst_dir.mkdir(parents=True, exist_ok=True)
    dst = dst_dir / "element_relations.json"
    dst.write_text(json.dumps(relations, ensure_ascii=False, indent=2), encoding="utf-8")

    print(f"OK [{game}]  {len(relations)} relations  ({skipped} valeurs ignorées)  → {dst.relative_to(ROOT)}")
    print(f"  Attaquants : {sorted(set(r['attacker'] for r in relations))}")

    # Couleurs → fichier dédié, idempotent côté seed
    if colors:
        dst_colors = dst_dir / "element_colors.json"
        payload = [{"name": n, "color": c} for n, c in colors.items()]
        dst_colors.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
        print(f"  {len(payload)} couleurs → {dst_colors.relative_to(ROOT)}")
        missing = [r for r in receivers if r not in colors]
        if missing:
            print(f"  WARN : sans couleur extractible : {missing}", file=sys.stderr)


def main() -> None:
    game = None
    src  = None
    for arg in sys.argv[1:]:
        if arg.startswith("--game="):
            game = arg.split("=", 1)[1].strip()
        elif arg.startswith("--file="):
            src = Path(arg.split("=", 1)[1].strip())
            if not src.is_absolute():
                src = ROOT / src
    if game is None or src is None:
        print("Usage : py tools/parse_element_relations.py --game=<slug> --file=<chemin.xlsx>", file=sys.stderr)
        sys.exit(2)
    process(game, src)


if __name__ == "__main__":
    sys.stdout.reconfigure(encoding="utf-8")
    main()
