"""Signed embed tokens for WordPress admin iframe sessions."""
from __future__ import annotations

import base64
import hashlib
import hmac
import json
import time
from typing import Any
from uuid import UUID, uuid4

from src.config import get_settings
from src.core.exceptions import ForbiddenError, ValidationError
from src.core.security.jwt import create_access_token
from src.domain.external_admin.wordpress_connect import _normalize_site_url


def issue_wordpress_embed_token(
    *,
    installation_id: str,
    project_id: str,
    workspace_id: str,
    site_url: str,
    ttl_seconds: int = 28800,
) -> str:
    settings = get_settings()
    payload: dict[str, Any] = {
        "installation_id": installation_id,
        "project_id": project_id,
        "workspace_id": workspace_id,
        "site_url": _normalize_site_url(site_url),
        "exp": int(time.time()) + ttl_seconds,
    }
    payload_b64 = base64.urlsafe_b64encode(json.dumps(payload, separators=(",", ":")).encode()).decode().rstrip("=")
    sig = hmac.new(
        settings.jwt_secret.encode(),
        payload_b64.encode(),
        hashlib.sha256,
    ).hexdigest()
    return f"{payload_b64}.{sig}"


def verify_wordpress_embed_token(embed_token: str, *, project_id: str | None = None) -> dict[str, Any]:
    embed_token = embed_token.strip()
    if "." not in embed_token:
        raise ValidationError("invalid_embed_token")

    payload_b64, sig = embed_token.rsplit(".", 1)
    expected = hmac.new(
        get_settings().jwt_secret.encode(),
        payload_b64.encode(),
        hashlib.sha256,
    ).hexdigest()
    if not hmac.compare_digest(expected, sig):
        raise ForbiddenError("invalid_embed_token_signature")

    padded = payload_b64 + "=" * (-len(payload_b64) % 4)
    try:
        payload = json.loads(base64.urlsafe_b64decode(padded.encode()))
    except (json.JSONDecodeError, ValueError) as exc:
        raise ValidationError("invalid_embed_token_payload") from exc

    if not isinstance(payload, dict):
        raise ValidationError("invalid_embed_token_payload")

    exp = int(payload.get("exp") or 0)
    if exp < int(time.time()):
        raise ForbiddenError("embed_token_expired")

    token_project_id = str(payload.get("project_id") or "").strip()
    if project_id and token_project_id != project_id:
        raise ForbiddenError("embed_token_project_mismatch")

    for key in ("installation_id", "project_id", "workspace_id", "site_url"):
        if not str(payload.get(key) or "").strip():
            raise ValidationError(f"embed_token_missing_{key}")

    return {
        "installation_id": str(payload["installation_id"]),
        "project_id": token_project_id,
        "workspace_id": str(payload["workspace_id"]),
        "site_url": str(payload["site_url"]),
    }


def mint_embed_access_token(user_id: UUID) -> tuple[str, int]:
    """Return a short-lived access token for iframe bootstrap."""
    settings = get_settings()
    session_id = uuid4()
    token = create_access_token(user_id, session_id)
    expires_at = int(time.time()) + settings.jwt_access_ttl_minutes * 60
    return token, expires_at
