import base64
import json
import time
import uuid

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

from .config import get_settings
from .errors import AppError


def _encode(value: bytes) -> str:
    return base64.urlsafe_b64encode(value).decode("ascii").rstrip("=")


def issue_computer_capability(
    *, scope: str, request_id: str, session_id: uuid.UUID | None = None,
    workspace_id: uuid.UUID | None = None, fencing_token: int | None = None,
    lifetime_seconds: int = 45,
) -> str:
    settings = get_settings()
    raw_key = settings.read_computer_capability_private_key()
    if not raw_key:
        raise AppError(
            "COMPUTER_CAPABILITY_UNCONFIGURED",
            "Computer capability signing is unconfigured.",
            503,
        )
    now = int(time.time())
    header = {
        "alg": "EdDSA", "typ": "HAYVA-CAP", "v": 1,
        "kid": settings.computer_capability_key_id,
    }
    claims = {
        "iss": "core-api", "aud": "computer-agent", "iat": now,
        "nbf": now - 2, "exp": now + lifetime_seconds, "jti": str(uuid.uuid4()),
        "scope": scope, "request_id": request_id,
    }
    if session_id:
        claims["session_id"] = str(session_id)
    if workspace_id:
        claims["workspace_id"] = str(workspace_id)
    if fencing_token is not None:
        claims["fencing_token"] = fencing_token
    encoded_header = _encode(json.dumps(
        header, sort_keys=True, separators=(",", ":")
    ).encode("utf-8"))
    encoded_claims = _encode(json.dumps(
        claims, sort_keys=True, separators=(",", ":")
    ).encode("utf-8"))
    signing_input = f"{encoded_header}.{encoded_claims}".encode("ascii")
    signature = Ed25519PrivateKey.from_private_bytes(raw_key).sign(signing_input)
    return f"{encoded_header}.{encoded_claims}.{_encode(signature)}"
