#!/usr/bin/env python3
"""regenerate-all.py — re-processar todos os logos com bg correto.

Source priority por slug:
  1. recursos/assets/logos/<slug>.png       (raw, melhor qualidade)
  2. recursos/assets/_logos.backup-before-svg-2026-04-24/<slug>.png (raw 128px)
  3. /tmp/logo-staging/<slug>.png|.svg       (fetched recente)
  4. pilot/public/tool-logos/<slug>.png      (fallback — circle existente)

Bg color priority:
  1. tool-logos-chip-overrides.json hex
  2. detect_bg() via edge ring
  3. auto_neutral() por luminance

Output: pilot/public/tool-logos/<slug>.png (sobrescreve)
"""
import json
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
from squircle import make_squircle

ROOT = Path("/root/nxt/terminal.net.br")
PILOT_SRC = ROOT / "projetos/terminal.net.br/src"
PUB = ROOT / "projetos/terminal.net.br/public/tool-logos"
ASSETS = ROOT / "recursos/assets"
TOOL_LOGOS = PILOT_SRC / "tool-logos.json"
CHIP_OVERRIDES = PILOT_SRC / "tool-logos-chip-overrides.json"

SOURCE_DIRS = [
    # /tmp/logo-staging/ = fetched fresh, top priority — overrides glyph
    # fallbacks in backup-before-svg que foram salvos como se fossem raws.
    Path("/tmp/logo-staging"),
    # _logos.backup-before-svg-2026-04-24 = true raws (128px) — MAS 20 files
    # foram corrompidos com placeholder do github (octocat). Filtro hash abaixo.
    ASSETS / "_logos.backup-before-svg-2026-04-24",
    # _logos.backup-2026-04-24 = snapshot mais antigo, sem corrupção, alguns
    # PNGs são variações (256px, 460px) mas conteúdo correto.
    ASSETS / "_logos.backup-2026-04-24",
    ASSETS / "logos",
    # circle/ tem versões já squircled — re-aplicar pipeline em cima é OK.
    # Útil pra ripgrep, swarmui, ttyd que só existem corrompidos nas outras dirs.
    ASSETS / "circle",
    PUB,  # ultimo recurso: re-aplica em si mesmo
]


# Pre-compute hash do github octocat em cada source dir (placeholder corruption marker).
import hashlib
_corrupt_hashes_per_dir: dict[Path, set[str]] = {}
for d in SOURCE_DIRS:
    gh = d / "github.png"
    if gh.exists():
        h = hashlib.md5(gh.read_bytes()).hexdigest()
        _corrupt_hashes_per_dir[d] = {h}


def _is_corrupt(path: Path) -> bool:
    """File hash matches github.png placeholder no mesmo dir → corrupted."""
    parent_hashes = _corrupt_hashes_per_dir.get(path.parent, set())
    if not parent_hashes:
        return False
    if path.name == "github.png":
        return False  # github.png itself é OK
    h = hashlib.md5(path.read_bytes()).hexdigest()
    return h in parent_hashes


def find_source(slug: str) -> Path | None:
    """Procura source raw em ordem de prioridade. Skip files corrompidos (hash igual ao github placeholder)."""
    candidates = [slug, slug.replace("-", "_"), slug.replace("_", "-")]
    for d in SOURCE_DIRS:
        for cand in candidates:
            for ext in (".png", ".svg"):
                p = d / f"{cand}{ext}"
                if p.exists() and p.stat().st_size > 100:
                    if _is_corrupt(p):
                        continue  # placeholder do github → tenta próxima fonte
                    return p
    return None


def slugify(s: str) -> str:
    import re
    return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-")


def process_one(slug: str, override_hex: str | None) -> dict:
    src = find_source(slug)
    if not src:
        return {"slug": slug, "ok": False, "error": "no source"}
    # Force white bg pra garantir contraste com logos escuros.
    # User feedback: "moldura branca atras de tudo" — ignora chip-overrides + auto-detect.
    forced_bg = "#ffffff"
    try:
        info = make_squircle(src, PUB / f"{slug}.png",
                             override_hex=forced_bg, desat=False, shape="circle")
        info["slug"] = slug
        info["ok"] = True
        info["source"] = str(src.relative_to(ROOT)) if ROOT in src.parents else str(src)
        return info
    except Exception as e:
        return {"slug": slug, "ok": False, "error": str(e)[:200]}


def main():
    # Load tool-logos: slugs com logoUrl=local:X
    with open(TOOL_LOGOS) as f:
        tool_logos = json.load(f)

    targets = []
    for name, entry in tool_logos.items():
        if name.startswith("_"):
            continue
        lurl = entry.get("logoUrl") or ""
        if lurl.startswith("local:"):
            slug = lurl[len("local:"):].replace(".png", "").replace(".svg", "")
            targets.append(slug)

    targets = sorted(set(targets))
    print(f"Targets: {len(targets)} slugs com logoUrl local")

    # Load chip overrides
    with open(CHIP_OVERRIDES) as f:
        chip = json.load(f)
    overrides = {k: v for k, v in chip.items() if k != "_note" and isinstance(v, str)}
    print(f"Manual chip overrides: {len(overrides)}")

    # Process
    results = []
    with ThreadPoolExecutor(max_workers=8) as ex:
        futures = {
            ex.submit(process_one, s, overrides.get(s) or overrides.get(s.replace("-", "_"))): s
            for s in targets
        }
        for i, fut in enumerate(as_completed(futures), 1):
            r = fut.result()
            results.append(r)
            if i % 100 == 0:
                ok = sum(1 for x in results if x["ok"])
                print(f"  {i}/{len(targets)} done, {ok} OK")

    ok = [r for r in results if r["ok"]]
    fail = [r for r in results if not r["ok"]]
    print(f"\nFinal: {len(ok)} OK, {len(fail)} FAIL")

    # By bg source
    by_bg = {}
    for r in ok:
        src = r["bg_source"].split(":")[0]
        by_bg[src] = by_bg.get(src, 0) + 1
    print(f"By bg source: {by_bg}")

    # Save report
    Path("/tmp/logo-staging-reports").mkdir(parents=True, exist_ok=True)
    with open("/tmp/logo-staging-reports/regenerate-all.json", "w") as f:
        json.dump({"ok": ok, "fail": fail, "by_bg": by_bg}, f, indent=2)

    if fail:
        print(f"\nFAILS:")
        for r in fail[:20]:
            print(f"  {r['slug']}: {r['error']}")


if __name__ == "__main__":
    main()
