"""ScopeWrit command-line interface."""

from __future__ import annotations

import argparse
import os
import sys
from pathlib import Path
from typing import Any

import uvicorn

from .api import api_key_sha256, create_app
from .benchmark import run_benchmark
from .canonical import canonical_json
from .crypto import (
    TrustStore,
    generate_keypair,
    load_private_key,
    load_public_key,
)
from .engine import ScopeWritEngine
from .errors import ScopeWritError
from .ledger import verify_audit_packet, verify_ledger
from .manifest_io import load_signed_manifest, sign_manifest_file
from .models import SignedEnvelope
from .perf import measure_policy_latency
from .inspect import inspect_manifest
from .manifest_io import load_manifest_yaml


def _json(value: Any) -> None:
    sys.stdout.buffer.write(canonical_json(value) + b"\n")


def _parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="scopewrit",
        description="Signed, deny-by-default run authority for autonomous agents.",
    )
    sub = parser.add_subparsers(dest="command", required=True)
    inspect = sub.add_parser("inspect", help="inspect an unsigned manifest before signing; grants no authority")
    inspect.add_argument("--manifest", required=True)

    keygen = sub.add_parser("keygen", help="generate an Ed25519 keypair")
    keygen.add_argument("--private", required=True)
    keygen.add_argument("--public", required=True)

    sign = sub.add_parser("sign", help="sign a strict YAML manifest")
    sign.add_argument("--manifest", required=True)
    sign.add_argument("--private-key", required=True)
    sign.add_argument("--key-id", required=True)
    sign.add_argument("--out", required=True)

    verify = sub.add_parser("verify-manifest", help="verify a signed manifest")
    verify.add_argument("--signed", required=True)
    verify.add_argument("--public-key", required=True)
    verify.add_argument("--key-id", required=True)

    benchmark = sub.add_parser(
        "benchmark",
        help="run the isolated guarded-versus-unguarded benchmark",
    )
    benchmark.add_argument("--output", required=True)

    measure = sub.add_parser(
        "measure",
        help="measure durable local authorization latency",
    )
    measure.add_argument("--output", required=True)
    measure.add_argument("--iterations", type=int, default=500)

    ledger = sub.add_parser("verify-ledger", help="verify a flight recorder")
    ledger.add_argument("--ledger", required=True)

    audit = sub.add_parser("verify-audit", help="verify an audit packet and ledger")
    audit.add_argument("--audit", required=True)
    audit.add_argument("--ledger", required=True)
    audit.add_argument("--public-key", required=True)
    audit.add_argument("--key-id", required=True)

    serve = sub.add_parser("serve", help="run the authenticated local control API")
    serve.add_argument("--data-dir", required=True)
    serve.add_argument("--principal-public-key", required=True)
    serve.add_argument("--principal-key-id", required=True)
    serve.add_argument("--issuer-private-key", required=True)
    serve.add_argument("--issuer-key-id", required=True)
    serve.add_argument("--host", default="127.0.0.1")
    serve.add_argument("--port", type=int, default=8765)
    serve.add_argument("--enable-http-egress", action="store_true")
    return parser


def main(argv: list[str] | None = None) -> int:
    args = _parser().parse_args(argv)
    try:
        if args.command == "inspect":
            result = inspect_manifest(load_manifest_yaml(args.manifest))
            _json(result)
            return 0 if result["valid"] else 2
        if args.command == "keygen":
            fingerprint = generate_keypair(args.private, args.public)
            _json(
                {
                    "status": "created",
                    "public_fingerprint_sha256": fingerprint,
                }
            )
            return 0
        if args.command == "sign":
            envelope = sign_manifest_file(
                manifest_path=args.manifest,
                destination=args.out,
                private_key=load_private_key(args.private_key),
                key_id=args.key_id,
            )
            _json(
                {
                    "status": "signed",
                    "payload_sha256": envelope.signature.payload_sha256,
                    "signer_fingerprint": envelope.signature.signer_fingerprint,
                }
            )
            return 0
        if args.command == "verify-manifest":
            manifest, envelope = load_signed_manifest(
                args.signed,
                TrustStore({args.key_id: load_public_key(args.public_key)}),
            )
            _json(
                {
                    "valid": True,
                    "run_id": manifest.run_id,
                    "mandate_id": manifest.mandate_id,
                    "payload_sha256": envelope.signature.payload_sha256,
                }
            )
            return 0
        if args.command == "benchmark":
            report = run_benchmark(args.output)
            _json(
                {
                    "verdict": report["verdict"],
                    "benchmark_id": report["benchmark_id"],
                    "report": str(Path(args.output).resolve() / "benchmark-report.json"),
                }
            )
            return 0 if report["verdict"] == "PASS" else 1
        if args.command == "measure":
            report = measure_policy_latency(
                args.output,
                iterations=args.iterations,
            )
            _json(
                {
                    "status": "measured",
                    "iterations_per_path": report["iterations_per_path"],
                    "allow_ticket_consume": report["allow_ticket_consume"],
                    "default_deny": report["default_deny"],
                    "report": str(Path(args.output).resolve() / "policy-latency.json"),
                }
            )
            return 0
        if args.command == "verify-ledger":
            _json(verify_ledger(args.ledger))
            return 0
        if args.command == "verify-audit":
            envelope = SignedEnvelope.model_validate_json(
                Path(args.audit).read_text(encoding="utf-8")
            )
            packet = verify_audit_packet(
                envelope,
                TrustStore({args.key_id: load_public_key(args.public_key)}),
                args.ledger,
            )
            _json({"valid": True, **packet.model_dump(mode="json")})
            return 0
        if args.command == "serve":
            api_key = os.environ.get("SCOPEWRIT_API_KEY")
            if not api_key or len(api_key) < 24:
                raise ScopeWritError("SCOPEWRIT_API_KEY must contain at least 24 characters")
            issuer_private = load_private_key(args.issuer_private_key)
            engine = ScopeWritEngine(
                data_dir=args.data_dir,
                principal_trust=TrustStore(
                    {args.principal_key_id: load_public_key(args.principal_public_key)}
                ),
                issuer_private_key=issuer_private,
                issuer_key_id=args.issuer_key_id,
            )
            app = create_app(
                engine,
                expected_api_key_sha256=api_key_sha256(api_key),
                enable_http_egress=args.enable_http_egress,
            )
            uvicorn.run(app, host=args.host, port=args.port)
            return 0
    except (ScopeWritError, OSError, ValueError) as exc:
        _json({"error": type(exc).__name__, "detail": str(exc)})
        return 2
    return 2


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