"""Versioned authenticated encryption for tenant credentials."""

from __future__ import annotations

import base64
import json
import os
from pathlib import Path
from dataclasses import dataclass

from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM


class SecretConfigurationError(RuntimeError):
    pass


class SecretIntegrityError(ValueError):
    pass


@dataclass(frozen=True)
class EncryptedSecret:
    ciphertext: str
    key_version: str


class VersionedAESCipher:
    """AES-256-GCM keyring with explicit active-key version."""

    FORMAT_VERSION = "aesgcm1"

    def __init__(self, keys: dict[str, bytes], active_version: str) -> None:
        if active_version not in keys:
            raise SecretConfigurationError("Active secret key version is not present in the keyring")
        for version, key in keys.items():
            if not version or len(key) != 32:
                raise SecretConfigurationError("Every platform secret key must be exactly 32 bytes")
        self.keys = keys
        self.active_version = active_version

    @classmethod
    def from_environment(cls) -> "VersionedAESCipher":
        keyring_file = Path(os.getenv(
            "PLATFORM_SECRETS_KEYRING_FILE",
            "/var/www/html/.platform-secrets/secrets-keyring.json",
        ))
        raw_keyring = os.getenv("PLATFORM_SECRETS_KEYS", "").strip()
        active_version = os.getenv("PLATFORM_SECRETS_ACTIVE_KEY_VERSION", "").strip()
        if not raw_keyring and keyring_file.is_file():
            try:
                file_payload = json.loads(keyring_file.read_text(encoding="utf-8"))
                raw_keyring = json.dumps(file_payload["keys"])
                active_version = str(file_payload["active_version"])
            except Exception as exc:
                raise SecretConfigurationError("External secret keyring file is invalid") from exc
        if not raw_keyring or not active_version:
            raise SecretConfigurationError(
                "An external platform secret keyring is required"
            )
        try:
            encoded_keys = json.loads(raw_keyring)
            keys = {
                str(version): base64.urlsafe_b64decode(str(encoded).encode("ascii"))
                for version, encoded in encoded_keys.items()
            }
        except Exception as exc:
            raise SecretConfigurationError("PLATFORM_SECRETS_KEYS is not a valid keyring") from exc
        return cls(keys, active_version)

    def encrypt(self, plaintext: str, *, aad: bytes) -> EncryptedSecret:
        nonce = os.urandom(12)
        encrypted = AESGCM(self.keys[self.active_version]).encrypt(
            nonce, plaintext.encode("utf-8"), aad,
        )
        payload = base64.urlsafe_b64encode(nonce + encrypted).decode("ascii")
        return EncryptedSecret(
            ciphertext=f"{self.FORMAT_VERSION}:{self.active_version}:{payload}",
            key_version=self.active_version,
        )

    def decrypt(self, ciphertext: str, *, aad: bytes) -> str:
        try:
            format_version, key_version, encoded = ciphertext.split(":", 2)
            if format_version != self.FORMAT_VERSION:
                raise SecretIntegrityError("Unsupported encrypted secret format")
            key = self.keys[key_version]
            payload = base64.urlsafe_b64decode(encoded.encode("ascii"))
            nonce, encrypted = payload[:12], payload[12:]
            return AESGCM(key).decrypt(nonce, encrypted, aad).decode("utf-8")
        except (KeyError, InvalidTag, UnicodeDecodeError, ValueError) as exc:
            if isinstance(exc, SecretIntegrityError):
                raise
            raise SecretIntegrityError("Encrypted secret failed integrity validation") from exc
