"""Legge i dati di un gioco dal portale BG Collection.

Usa l'endpoint /api/gioco/{id}, che restituisce JSON pulito. Il portale non
espone un elenco: la lista dei giochi si ricava dalla home (link /gioco/<id>
con il titolo nell'attributo title), che mostra i giochi posseduti da Paolo.
"""
import json, os, time, urllib.request, urllib.error

BASE = "https://bgcollezione.vercel.app/api/gioco/"
CACHE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "dati", "cache", "api")
UA = "bg-perspective-generator/1.0 (uso personale, contatto via il proprietario del sito)"

# Soglie del peso BGG, tarate sulla distribuzione reale dell'archivio
# (mediana 2,24, massimo 4,82): a terzi uguali fra 1 e 5 finirebbe quasi tutto
# nel livello basso. Quattro livelli, tutti corti abbastanza da stare su una riga.
SOGLIE_PESO = ((2.0, "Leggero"), (3.0, "Medio"), (3.8, "Impegnativo"), (99.0, "Per esperti"))

# Sopra 3,8 un gestionale si chiama "Cinghiale": gergo vero, ma solo per gli
# eurogame. La regola guarda categorie e meccaniche.
CATEGORIE_CINGHIALE = {"Economia", "Industria", "Agricoltura", "Costruzione Città", "Costruzione di Città"}
MECCANICHE_CINGHIALE = {"Piazzamento Lavoratori", "Piazzamento lavoratori"}


def etichetta_peso(peso, categorie=(), meccaniche=()):
    if peso is None:
        return None
    for limite, nome in SOGLIE_PESO:
        if peso < limite:
            if nome == "Per esperti" and (set(categorie) & CATEGORIE_CINGHIALE
                                          or set(meccaniche) & MECCANICHE_CINGHIALE):
                return "Cinghiale"
            return nome
    return None


def _derivati(d):
    """Campi calcolati al volo. Non finiscono in cache: cosi' cambiando le
    soglie del peso si aggiornano tutti i giochi senza svuotare niente."""
    cat = [c["nome"] if isinstance(c, dict) else c for c in (d.get("categorie") or [])]
    mec = [m["nome"] if isinstance(m, dict) else m for m in (d.get("meccaniche") or [])]
    d["categorieNomi"], d["meccanicheNomi"] = cat, mec
    d["pesoEtichetta"] = etichetta_peso(d.get("peso"), cat, mec)
    d["autoriNomi"] = [a["nome"] for a in (d.get("autori") or []) if a.get("nome")]
    return d


def dati_gioco(bgg_id, usa_cache=True, pausa=0.15):
    """Restituisce il dizionario del gioco, o {'errore': ...} se non ci riesce."""
    os.makedirs(CACHE, exist_ok=True)
    percorso = os.path.join(CACHE, f"{bgg_id}.json")

    if usa_cache and os.path.exists(percorso):
        try:
            with open(percorso, encoding="utf-8") as f:
                return _derivati(json.load(f))
        except (json.JSONDecodeError, OSError):
            pass  # cache illeggibile: si riscarica

    req = urllib.request.Request(BASE + str(bgg_id), headers={"User-Agent": UA})
    try:
        with urllib.request.urlopen(req, timeout=25) as r:
            d = json.load(r)
    except urllib.error.HTTPError as e:
        return {"errore": f"HTTP {e.code}", "id": bgg_id}
    except Exception as e:
        return {"errore": str(e), "id": bgg_id}

    with open(percorso, "w", encoding="utf-8") as f:
        json.dump(d, f, ensure_ascii=False)
    if pausa:
        time.sleep(pausa)
    return _derivati(d)


def credits(d):
    """La riga della copertina: autori, anno, editore italiano."""
    pezzi = []
    autori = d.get("autoriNomi") or []
    if autori:
        pezzi.append(" e ".join(autori[:2]) if len(autori) <= 2 else autori[0] + " e altri")
    if d.get("anno"):
        pezzi.append(str(d["anno"]))
    ed = d.get("editoreIt")
    riga = " · ".join(pezzi)
    return f"{riga} · <b>{ed}</b>" if ed else riga


def giocatori(d):
    a, b = d.get("minPlayers"), d.get("maxPlayers")
    if not a and not b:
        return None
    return str(a) if a == b else f"{a}–{b}"


def durata_scatola(d):
    a, b = d.get("minPlaytime"), d.get("maxPlaytime")
    if not a and not b:
        return None
    return f"{a}′" if a == b else f"{a}–{b}′"


SCATOLE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scatole")


def scatola_bgg(bgg_id, nome, riscarica=False):
    """Scarica la copertina da BGG in `scatole/grezze/` e restituisce il percorso.

    **Questa e' la fonte da preferire.** BGG pubblica la copertina piatta, gia'
    ritagliata, senza fondo da togliere. DungeonDice invece mette render della
    scatola in prospettiva su bianco, che vanno scontornati, e lo scontorno
    fallisce quando il fronte della scatola e' chiaro: su Faraway il
    riempimento e' entrato dal bordo e ha bucato la copertina, lasciando sul
    nero solo l'illustrazione che galleggiava.

    **L'imprevisto da controllare a occhio ogni volta e' la lingua.** BGG mostra
    l'edizione principale, non quella italiana: su Terraforming Mars la
    copertina di BGG e' inglese (Stronghold Games) mentre la scatola Ghenos ha
    il titolo e il claim tradotti, e li' va tenuta quella di DungeonDice. Se
    cambia solo il logo dell'editore in basso, che sulla slide e' alto una
    quindicina di pixel, la copertina di BGG va bene lo stesso.
    """
    import urllib.request
    grezze = os.path.join(SCATOLE, "grezze")
    os.makedirs(grezze, exist_ok=True)
    d = dati_gioco(bgg_id)
    url = d.get("image")
    if not url:
        return None
    ext = url.rsplit(".", 1)[-1].split("?")[0]
    dst = os.path.join(grezze, f"bgg_{nome}.{ext}")
    if riscarica or not os.path.exists(dst):
        req = urllib.request.Request(url, headers={"User-Agent": UA})
        with urllib.request.urlopen(req, timeout=60) as r, open(dst, "wb") as f:
            f.write(r.read())
    return dst


if __name__ == "__main__":
    import sys
    for gid in (sys.argv[1:] or ["264055"]):
        d = dati_gioco(gid)
        if d.get("errore"):
            print(gid, "ERRORE", d["errore"]); continue
        print(f"{d['nome']} ({d.get('anno')})")
        print("  credits:", credits(d))
        print("  giocatori:", giocatori(d), "| durata:", durata_scatola(d),
              "| peso:", d.get("peso"), "->", d.get("pesoEtichetta"))
        print("  editore it:", d.get("editoreIt"), "| da verificare:", d.get("editoreItDaVerificare"))
