"""Generation du graphe JSON-LD schema.org (hand-off pour injection dans les pages).

Un noeud `Organization` (marque publique · #4) + un noeud `listing_type`
(defaut `Residence`) par projet du master.

ANTI-INVENTION (#6 · #10) : un projet n'expose une `offers`/`price` QUE s'il est
`disponible` ET qu'une de ses typologies porte un `prix_depuis_usd` numerique
sourcE dans le master. Pour tout statut de `STATUTS_SANS_PRIX` (en_developpement,
bientot, en_processus) : AUCUN prix (jamais de chiffre fabrique). Devise = USD
(devise primaire #10). Aucune horloge, tri stable -> sortie diffable.
"""

from __future__ import annotations

from . import deps


def _is_number(value) -> bool:
    return isinstance(value, (int, float)) and not isinstance(value, bool)


def _offers_for(projet: dict) -> list[dict]:
    """Offres schema.org d'un projet — vide si non `disponible` ou sans prix sourcE."""
    if projet["statut"] in deps.STATUTS_SANS_PRIX:
        return []
    offers = []
    for typo in projet.get("typologies", []):
        price = typo.get("prix_depuis_usd")
        if _is_number(price):
            offers.append({
                "@type": "Offer",
                "name": typo.get("nom"),
                "price": price,
                "priceCurrency": deps.DEVISE_PRIMAIRE,
                "availability": "https://schema.org/InStock",
            })
    return offers


def generate(spec: dict, master: dict) -> dict:
    so = spec["schema_org"]
    base = spec["site"]["base_url"].rstrip("/")
    org_id = f"{base}/#organization"
    org = so["organization"]

    graph: list[dict] = [{
        "@type": org["type"],
        "@id": org_id,
        "name": org["name"],
        "url": org["url"],
    }]

    for p in master["projets"]:
        slug = deps.slugify(p["nom"])
        node = {
            "@type": so["listing_type"],
            "@id": f"{base}/projets/{slug}#residence",
            "name": p["nom"],
            "url": f"{base}/projets/{slug}",
            "brand": {"@id": org_id},
            "address": {
                "@type": "PostalAddress",
                "addressCountry": so["country_code"],
                "addressLocality": p["localisation"],
            },
        }
        offers = _offers_for(p)
        if offers:
            node["offers"] = offers
        graph.append(node)

    return {"@context": so["context"], "@graph": graph}
