#!/usr/bin/env python3
"""Publiciste Agent · orchestrateur CLI (scaffold Sprint 2).

Cible de portage sur le VPS : `otoia/capabilities/publiciste.py`
(cf. 03_agents/publiciste/AGENT.md · GAP_ANALYSIS_SPRINT1.md §3.13).

Maintient le site public `vente.otov7.com` À PARTIR DES FAISABILITÉS CANONIQUES
(data_room/PXX/), sans édition manuelle. Zéro invention de chiffre (CLAUDE.md #6).

Sous-commandes :
  parse     data_room/  -> projets_master.json (validé contre le schéma)
  validate  projets_master.json
  generate  projets_master.json -> index.html
  run       data_room/  -> projets_master.json + index.html (pipeline complet)

Pipeline (AGENT.md §Architecture technique) :
  data_room/PXX/ ──► parser ──► projets_master.json ──► generator ──► index.html

⚠ Ce worker n'écrit JAMAIS sur le VPS. La commande `run` produit les artefacts
dans un dossier de sortie local ; le déploiement réel (copie vers
/opt/oto/sites/vente/ + cache-bust + WhatsApp) est un livrable ultérieur exécuté
côté serveur par l'agent (Semaines 4-5).
"""

from __future__ import annotations

import argparse
import json
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from lib import generator, parser, validator  # noqa: E402

_SCHEMA_DIR = os.path.normpath(
    os.path.join(os.path.dirname(__file__), "..", "faisabilite")
)


def _load_schema(name: str) -> dict:
    with open(os.path.join(_SCHEMA_DIR, name), encoding="utf-8") as fh:
        return json.load(fh)


def _eprint(*args) -> None:
    print(*args, file=sys.stderr)


# --------------------------------------------------------------------------- #
def cmd_parse(ns: argparse.Namespace) -> int:
    master = parser.build_master(ns.data_room, generated_at=ns.generated_at)
    errors = validator.validate(master, _load_schema("projets_master.schema.json"))
    if errors:
        _eprint("❌ projets_master.json NON conforme au schéma :")
        for e in errors:
            _eprint("   ·", e)
        # On écrit quand même la sortie pour diagnostic si --force.
        if not ns.force:
            return 1
    payload = json.dumps(master, ensure_ascii=False, indent=2)
    if ns.out:
        with open(ns.out, "w", encoding="utf-8") as fh:
            fh.write(payload + "\n")
        _eprint(f"✅ {len(master['projets'])} projet(s) → {ns.out}")
    else:
        print(payload)
    return 0


def cmd_validate(ns: argparse.Namespace) -> int:
    with open(ns.master, encoding="utf-8") as fh:
        master = json.load(fh)
    errors = validator.validate(master, _load_schema("projets_master.schema.json"))
    if errors:
        _eprint(f"❌ {ns.master} : {len(errors)} erreur(s)")
        for e in errors:
            _eprint("   ·", e)
        return 1
    _eprint(f"✅ {ns.master} conforme ({len(master.get('projets', []))} projet(s)).")
    return 0


def cmd_generate(ns: argparse.Namespace) -> int:
    with open(ns.master, encoding="utf-8") as fh:
        master = json.load(fh)
    errors = validator.validate(master, _load_schema("projets_master.schema.json"))
    if errors and not ns.force:
        _eprint("❌ master non conforme — génération refusée (voir `validate`). --force pour outrepasser.")
        return 1
    html_out = generator.render_site(master)
    if ns.out:
        with open(ns.out, "w", encoding="utf-8") as fh:
            fh.write(html_out)
        _eprint(f"✅ site généré → {ns.out} ({len(master.get('projets', []))} projet(s))")
    else:
        sys.stdout.write(html_out)
    return 0


def cmd_run(ns: argparse.Namespace) -> int:
    os.makedirs(ns.out_dir, exist_ok=True)
    master = parser.build_master(ns.data_room, generated_at=ns.generated_at)
    schema = _load_schema("projets_master.schema.json")
    errors = validator.validate(master, schema)
    master_path = os.path.join(ns.out_dir, "projets_master.json")
    with open(master_path, "w", encoding="utf-8") as fh:
        fh.write(json.dumps(master, ensure_ascii=False, indent=2) + "\n")
    if errors:
        _eprint(f"❌ master non conforme ({len(errors)} erreur(s)) — index NON généré.")
        for e in errors:
            _eprint("   ·", e)
        return 1
    html_out = generator.render_site(master)
    index_path = os.path.join(ns.out_dir, "index.html")
    with open(index_path, "w", encoding="utf-8") as fh:
        fh.write(html_out)
    _eprint(f"✅ pipeline OK — {len(master['projets'])} projet(s)")
    _eprint(f"   · {master_path}")
    _eprint(f"   · {index_path}")
    return 0


# --------------------------------------------------------------------------- #
def build_argparser() -> argparse.ArgumentParser:
    ap = argparse.ArgumentParser(prog="publiciste", description=__doc__.splitlines()[0])
    sub = ap.add_subparsers(dest="cmd", required=True)

    p = sub.add_parser("parse", help="data_room/ -> projets_master.json")
    p.add_argument("data_room")
    p.add_argument("-o", "--out")
    p.add_argument("--generated-at", dest="generated_at", default=None)
    p.add_argument("--force", action="store_true", help="écrire même si non conforme")
    p.set_defaults(func=cmd_parse)

    p = sub.add_parser("validate", help="valide un projets_master.json")
    p.add_argument("master")
    p.set_defaults(func=cmd_validate)

    p = sub.add_parser("generate", help="projets_master.json -> index.html")
    p.add_argument("master")
    p.add_argument("-o", "--out")
    p.add_argument("--force", action="store_true")
    p.set_defaults(func=cmd_generate)

    p = sub.add_parser("run", help="pipeline complet data_room/ -> out_dir/")
    p.add_argument("data_room")
    p.add_argument("-o", "--out-dir", dest="out_dir", default="build")
    p.add_argument("--generated-at", dest="generated_at", default=None)
    p.set_defaults(func=cmd_run)
    return ap


def main(argv: list[str] | None = None) -> int:
    ns = build_argparser().parse_args(argv)
    return ns.func(ns)


if __name__ == "__main__":
    raise SystemExit(main())
