from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT / "backend"))

from flexiforge.geometry import analyse_mesh, load_mesh, repair_mesh  # noqa: E402
from flexiforge.shire_bridge import ShireJobStore  # noqa: E402

DATA = ROOT / "data"
STORE = ShireJobStore(DATA / "shire_jobs", DATA / "models", DATA / "exports")


def emit(value):
    print(json.dumps(value, indent=2, sort_keys=True))


def import_source(path: Path) -> str:
    import hashlib
    import shutil

    source = path.expanduser().resolve()
    if not source.exists() or source.suffix.lower() != ".stl":
        raise SystemExit(f"STL not found: {source}")
    digest = hashlib.sha256(source.read_bytes()).hexdigest()[:24]
    model_id = f"cli-{digest}"
    target = DATA / "models" / f"{model_id}.stl"
    target.parent.mkdir(parents=True, exist_ok=True)
    mesh = load_mesh(source)
    mesh, notes = repair_mesh(mesh)
    mesh.apply_translation(-mesh.centroid)
    mesh.export(target)
    (target.with_suffix(".json")).write_text(
        json.dumps({"original_name": source.name, "analysis": analyse_mesh(mesh, notes).__dict__}, indent=2),
        encoding="utf-8",
    )
    return model_id


def main() -> None:
    parser = argparse.ArgumentParser(description="Approval-gated SHiRE bridge for FlexiForge")
    sub = parser.add_subparsers(dest="command", required=True)

    p = sub.add_parser("create")
    p.add_argument("--source", required=True, type=Path)
    p.add_argument("--project", required=True)
    p.add_argument("--intent", default="Turn this STL into an articulated fidget.")
    p.add_argument("--movement", default="auto", choices=["auto", "bend", "wiggle", "rotate", "ball"])
    p.add_argument("--clearance", type=float, default=0.35)

    p = sub.add_parser("show"); p.add_argument("job_id")
    p = sub.add_parser("select"); p.add_argument("job_id"); p.add_argument("suggestion_id"); p.add_argument("--joint", default="auto", choices=["auto", "hinge", "flexi", "ball_socket"])
    p = sub.add_parser("request-design-approval"); p.add_argument("job_id")
    p = sub.add_parser("approve-design"); p.add_argument("job_id"); p.add_argument("token")
    p = sub.add_parser("forge"); p.add_argument("job_id")
    p = sub.add_parser("validate"); p.add_argument("job_id")
    p = sub.add_parser("request-export-approval"); p.add_argument("job_id")
    p = sub.add_parser("approve-export"); p.add_argument("job_id"); p.add_argument("token")
    p = sub.add_parser("export"); p.add_argument("job_id"); p.add_argument("--vault-root", type=Path)

    args = parser.parse_args()
    if args.command == "create":
        model_id = import_source(args.source)
        emit(STORE.create_job(model_id, args.project, args.intent, args.movement, args.clearance, 5))
    elif args.command == "show": emit(STORE.get(args.job_id))
    elif args.command == "select": emit(STORE.select_suggestion(args.job_id, args.suggestion_id, args.joint))
    elif args.command == "request-design-approval": emit({"approval_token": STORE.approval_token(args.job_id, "design")})
    elif args.command == "approve-design": emit(STORE.approve(args.job_id, "design", args.token))
    elif args.command == "forge": emit(STORE.forge(args.job_id))
    elif args.command == "validate": emit(STORE.validate(args.job_id))
    elif args.command == "request-export-approval": emit({"approval_token": STORE.approval_token(args.job_id, "export")})
    elif args.command == "approve-export": emit(STORE.approve(args.job_id, "export", args.token))
    elif args.command == "export": emit(STORE.export_to_vault(args.job_id, args.vault_root))


if __name__ == "__main__":
    main()
