"""Pydantic models for the secrets module."""

from __future__ import annotations

import re
from datetime import datetime

from pydantic import BaseModel, Field, field_validator

# Valid secret name pattern
SECRET_NAME_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")


def validate_secret_name(name: str) -> str:
    """Validate a secret name."""
    if not SECRET_NAME_PATTERN.match(name):
        from gaol.secrets.exceptions import InvalidSecretNameError

        raise InvalidSecretNameError(name)
    return name


class EncryptedSecret(BaseModel):
    """An encrypted secret stored on disk."""

    name: str
    encrypted_value: str  # Base64-encoded encrypted data (nonce + ciphertext)
    created_at: datetime
    updated_at: datetime
    description: str | None = None

    @field_validator("name")
    @classmethod
    def check_name(cls, v: str) -> str:
        """Validate the secret name."""
        return validate_secret_name(v)


class SecretsConfig(BaseModel):
    """Configuration for the secrets store."""

    version: int = 1
    salt: str  # Base64-encoded salt for key derivation (when using password)
    kdf_iterations: int = 600_000  # PBKDF2 iterations
    encryption_algorithm: str = "AES-256-GCM"


class SecretMetadata(BaseModel):
    """Metadata about a secret (without the value)."""

    name: str
    created_at: datetime
    updated_at: datetime
    description: str | None = None


class SecretsStore(BaseModel):
    """The secrets store file format."""

    config: SecretsConfig
    secrets: dict[str, EncryptedSecret] = Field(default_factory=dict)

    def add_secret(self, secret: EncryptedSecret) -> None:
        """Add or update a secret."""
        self.secrets[secret.name] = secret

    def get_secret(self, name: str) -> EncryptedSecret | None:
        """Get an encrypted secret by name."""
        return self.secrets.get(name)

    def remove_secret(self, name: str) -> bool:
        """Remove a secret, returns True if it existed."""
        if name in self.secrets:
            del self.secrets[name]
            return True
        return False

    def list_metadata(self) -> list[SecretMetadata]:
        """Get metadata for all secrets."""
        return [
            SecretMetadata(
                name=s.name,
                created_at=s.created_at,
                updated_at=s.updated_at,
                description=s.description,
            )
            for s in self.secrets.values()
        ]
