"""Reproducible local admission-latency measurement."""

from __future__ import annotations

import platform
import sys
import time
import uuid
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Any

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

from .canonical import canonical_json
from .crypto import TrustStore, sign_envelope
from .engine import ScopeWritEngine
from .models import ActionProposal, Decision, Effect, ScopeManifest, ScopeRule


def _summary(values_ns: list[int]) -> dict[str, float]:
    ordered = sorted(value / 1_000_000 for value in values_ns)

    def percentile(fraction: float) -> float:
        index = min(len(ordered) - 1, int((len(ordered) - 1) * fraction))
        return round(ordered[index], 4)

    return {
        "min_ms": round(ordered[0], 4),
        "median_ms": percentile(0.5),
        "p95_ms": percentile(0.95),
        "p99_ms": percentile(0.99),
        "max_ms": round(ordered[-1], 4),
        "mean_ms": round(sum(ordered) / len(ordered), 4),
    }


def measure_policy_latency(
    output_dir: str | Path,
    *,
    iterations: int = 500,
) -> dict[str, Any]:
    if not 10 <= iterations <= 100_000:
        raise ValueError("iterations must be between 10 and 100000")
    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)
    principal = Ed25519PrivateKey.generate()
    issuer = Ed25519PrivateKey.generate()
    now = datetime.now(UTC)
    run_id = f"run-{uuid.uuid4().hex}"
    manifest = ScopeManifest(
        mandate_id=f"mandate-{uuid.uuid4().hex}",
        run_id=run_id,
        principal="latency-benchmark",
        agent_id="latency-probe",
        objective=(
            "Measure durable allow-ticket-consume and default-deny latency "
            "without invoking an external tool."
        ),
        issued_at=now,
        not_before=now,
        expires_at=now + timedelta(hours=1),
        nonce=uuid.uuid4().hex,
        rules=(
            ScopeRule(
                rule_id="allow-inspect",
                effect=Effect.ALLOW,
                action="mcp.call",
                resource="mcp://benchmark/inspect",
                max_uses=iterations,
            ),
        ),
        pause_on_scope_uncertainty=False,
        claim_boundary=(
            "This local measurement includes signature verification, SQLite "
            "state, ticket mint/consume, and fsynced JSONL recording. It does "
            "not include network or upstream tool latency."
        ),
    )
    envelope = sign_envelope(
        manifest.model_dump(mode="json"),
        principal,
        "latency-principal",
    )
    engine = ScopeWritEngine(
        data_dir=output / "runtime",
        principal_trust=TrustStore({"latency-principal": principal.public_key()}),
        issuer_private_key=issuer,
        issuer_key_id="latency-issuer",
    )
    start = engine.start_run(envelope)

    allow_ns: list[int] = []
    deny_ns: list[int] = []
    for index in range(iterations):
        proposal = ActionProposal(
            request_id=f"allow-{index:06d}",
            run_id=run_id,
            action="mcp.call",
            resource="mcp://benchmark/inspect",
            attributes={"arguments_sha256": "0" * 64},
        )
        before = time.perf_counter_ns()
        decision = engine.authorize(
            attestation=start.attestation,
            proposal=proposal,
        )
        if decision.decision != Decision.ALLOW or decision.ticket is None:
            raise RuntimeError("latency benchmark allow invariant failed")
        engine.consume_ticket(
            decision.ticket,
            proposal=proposal,
            adapter="mcp",
        )
        allow_ns.append(time.perf_counter_ns() - before)
        engine.record_execution(
            proposal=proposal,
            outcome={
                "status": "not_executed",
                "reason": "authorization latency control; no external operation",
            },
        )

    for index in range(iterations):
        proposal = ActionProposal(
            request_id=f"deny-{index:06d}",
            run_id=run_id,
            action="mcp.call",
            resource="mcp://benchmark/delete",
            attributes={"arguments_sha256": "0" * 64},
        )
        before = time.perf_counter_ns()
        decision = engine.authorize(
            attestation=start.attestation,
            proposal=proposal,
        )
        if decision.decision != Decision.DENY:
            raise RuntimeError("latency benchmark deny invariant failed")
        deny_ns.append(time.perf_counter_ns() - before)

    audit = engine.close_run(run_id)
    report = {
        "schema_version": "1.0",
        "generated_at": datetime.now(UTC).isoformat(),
        "iterations_per_path": iterations,
        "environment": {
            "platform": platform.platform(),
            "python": sys.version.split()[0],
        },
        "allow_ticket_consume": _summary(allow_ns),
        "default_deny": _summary(deny_ns),
        "claim_boundary": manifest.claim_boundary,
        "audit_packet": audit.model_dump(mode="json"),
    }
    (output / "policy-latency.json").write_bytes(canonical_json(report) + b"\n")
    return report
