"""JWTs for P2HS Cloud: long-lived authorization binding + short-lived execution grant."""
from __future__ import annotations

from datetime import datetime, timedelta, timezone
from typing import Any, Optional
from uuid import UUID, uuid4

from jose import JWTError, jwt

from src.config import get_settings


def _signing_secret() -> str:
    s = get_settings()
    secret = s.cloud_grant_jwt_secret.strip()
    if secret:
        return secret
    if not s.is_dev:
        raise RuntimeError(
            "CLOUD_GRANT_JWT_SECRET is not set. Refusing to fall back to the general "
            "session JWT_SECRET outside dev — a leak of that much larger-attack-surface "
            "secret would otherwise let an attacker forge Cloud execution grants for any "
            "workspace/project. Set CLOUD_GRANT_JWT_SECRET explicitly for this environment."
        )
    return s.jwt_secret.strip()


def create_cloud_authorization_token(
    *,
    workspace_id: UUID,
    project_id: UUID,
    request_type: str,
    idempotency_key: str,
) -> tuple[str, str]:
    """Return (authorization_id JWT, jti) — self-contained; no Redis. TTL ~7 days."""
    s = get_settings()
    now = datetime.now(timezone.utc)
    ttl_days = max(1, min(s.cloud_authorization_token_ttl_days, 30))
    expire = now + timedelta(days=ttl_days)
    jti = str(uuid4())
    payload: dict[str, Any] = {
        "typ": "p2hs_cloud_authz",
        "iss": "p2hs-core",
        "aud": "p2hs-cloud",
        "ws": str(workspace_id),
        "pid": str(project_id),
        "rt": request_type,
        "idem": idempotency_key,
        "jti": jti,
        "iat": now,
        "exp": expire,
    }
    return jwt.encode(payload, _signing_secret(), algorithm="HS256"), jti


def decode_cloud_authorization_token(token: str) -> Optional[dict[str, Any]]:
    """Validate Core-issued authorization_id JWT."""
    try:
        return jwt.decode(
            token,
            _signing_secret(),
            algorithms=["HS256"],
            audience="p2hs-cloud",
            options={"require": ["exp", "iat"]},
        )
    except JWTError:
        return None


def create_connector_approval_token(
    *,
    workspace_id: UUID,
    project_id: UUID,
    connection_id: UUID,
    action_slug: str,
    user_id: Optional[UUID] = None,
    run_id: Optional[UUID] = None,
    ttl_minutes: int = 10,
) -> tuple[str, datetime]:
    """Short-lived signed approval for connector actions whose policy is ``ask``."""
    now = datetime.now(timezone.utc)
    expire = now + timedelta(minutes=max(1, min(ttl_minutes, 60)))
    payload: dict[str, Any] = {
        "typ": "p2hs_connector_approval",
        "iss": "p2hs-core",
        "aud": "p2hs-core",
        "ws": str(workspace_id),
        "pid": str(project_id),
        "cid": str(connection_id),
        "act": action_slug,
        "jti": str(uuid4()),
        "iat": now,
        "exp": expire,
    }
    if user_id is not None:
        payload["uid"] = str(user_id)
    if run_id is not None:
        payload["rid"] = str(run_id)
    return jwt.encode(payload, _signing_secret(), algorithm="HS256"), expire


def decode_connector_approval_token(token: str) -> Optional[dict[str, Any]]:
    """Validate a Core-issued connector approval JWT."""
    try:
        payload = jwt.decode(
            token,
            _signing_secret(),
            algorithms=["HS256"],
            audience="p2hs-core",
            options={"require": ["exp", "iat"]},
        )
    except JWTError:
        return None
    if payload.get("typ") != "p2hs_connector_approval":
        return None
    return payload


def create_cloud_grant_jwt(
    *,
    workspace_id: UUID,
    project_id: UUID,
    authorization_jti: str,
    request_type: str,
    policy_capability: str,
    policy_provider: Optional[str],
    max_attempts: int,
    max_runtime_seconds: int,
    requires_webhook: bool,
    artifact_retention_days: int,
    extra_claims: Optional[dict[str, Any]] = None,
) -> tuple[str, datetime]:
    """Short-lived grant executed by pc-processor. Returns (jwt, expires_at_utc)."""
    s = get_settings()
    now = datetime.now(timezone.utc)
    ttl_min = max(5, min(s.cloud_grant_ttl_minutes, 120))
    # Voice sessions can last far longer than the default 15-minute grant.
    if max_runtime_seconds and max_runtime_seconds > ttl_min * 60:
        ttl_min = min(24 * 60, max(ttl_min, (max_runtime_seconds + 299) // 60))
    expire = now + timedelta(minutes=ttl_min)
    payload: dict[str, Any] = {
        "typ": "p2hs_cloud_grant",
        "iss": "p2hs-core",
        "aud": "p2hs-cloud",
        "ws": str(workspace_id),
        "pid": str(project_id),
        "sub": request_type,
        "az_jti": authorization_jti,
        "cap": policy_capability,
        "pv": policy_provider,
        "max_attempts": max_attempts,
        "max_runtime_seconds": max_runtime_seconds,
        "requires_webhook": requires_webhook,
        "artifact_retention_days": artifact_retention_days,
        "iat": now,
        "exp": expire,
    }
    if extra_claims:
        payload.update(extra_claims)
    token = jwt.encode(payload, _signing_secret(), algorithm="HS256")
    return token, expire


def decode_cloud_grant_jwt(token: str) -> Optional[dict[str, Any]]:
    try:
        payload = jwt.decode(
            token,
            _signing_secret(),
            algorithms=["HS256"],
            audience="p2hs-cloud",
            options={"require": ["exp", "iat"]},
        )
    except JWTError:
        return None
    if payload.get("typ") != "p2hs_cloud_grant":
        return None
    return payload
