"""Domain models for secrets management."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

from pydantic import BaseModel, Field


def _utcnow() -> datetime:
    return datetime.now(timezone.utc)


class AccessPolicy(BaseModel):
    """Controls which services and roles can read a secret."""

    allowed_services: list[str] = Field(default_factory=list)
    allowed_roles: list[str] = Field(default_factory=list)

    def allows(self, *, service: str | None = None, role: str | None = None) -> bool:
        """Return True if the given service or role is permitted."""
        if not self.allowed_services and not self.allowed_roles:
            return True
        service_ok = not self.allowed_services or (service in self.allowed_services)
        role_ok = not self.allowed_roles or (role in self.allowed_roles)
        return service_ok and role_ok


class SecretVersion(BaseModel):
    """A single versioned snapshot of a secret's encrypted value."""

    version_number: int
    encrypted_value: bytes
    created_at: datetime = Field(default_factory=_utcnow)
    created_by: str = ""


class Secret(BaseModel):
    """Core secret entity with encryption, versioning, and access control."""

    id: str
    name: str
    encrypted_value: bytes
    version: int = 1
    created_at: datetime = Field(default_factory=_utcnow)
    updated_at: datetime = Field(default_factory=_utcnow)
    expires_at: datetime | None = None
    tags: dict[str, str] = Field(default_factory=dict)
    access_policy: AccessPolicy = Field(default_factory=AccessPolicy)
    versions: list[SecretVersion] = Field(default_factory=list)
    deleted: bool = False

    model_config = {"arbitrary_types_allowed": True}


class SecretMetadata(BaseModel):
    """Safe-to-list metadata for a secret (no encrypted value)."""

    name: str
    version: int
    tags: dict[str, str] = Field(default_factory=dict)
    created_at: datetime = Field(default_factory=_utcnow)
    updated_at: datetime = Field(default_factory=_utcnow)
    expires_at: datetime | None = None

    @classmethod
    def from_secret(cls, secret: Secret) -> SecretMetadata:
        return cls(
            name=secret.name,
            version=secret.version,
            tags=secret.tags,
            created_at=secret.created_at,
            updated_at=secret.updated_at,
            expires_at=secret.expires_at,
        )


# --- API request/response schemas ---


class SecretCreateRequest(BaseModel):
    """Payload for creating a new secret."""

    name: str
    value: str
    tags: dict[str, str] = Field(default_factory=dict)
    expires_at: datetime | None = None
    allowed_services: list[str] = Field(default_factory=list)
    allowed_roles: list[str] = Field(default_factory=list)


class SecretUpdateRequest(BaseModel):
    """Payload for updating (rotating) an existing secret."""

    value: str
    tags: dict[str, str] | None = None


class SecretResponse(BaseModel):
    """Response containing a decrypted secret value."""

    name: str
    value: str
    version: int
    tags: dict[str, str] = Field(default_factory=dict)
    created_at: datetime
    updated_at: datetime
    expires_at: datetime | None = None


class SecretMetadataResponse(BaseModel):
    """Listing response without the secret value."""

    name: str
    version: int
    tags: dict[str, str] = Field(default_factory=dict)
    created_at: datetime
    updated_at: datetime
    expires_at: datetime | None = None


class SecretVersionResponse(BaseModel):
    """A version entry in the history listing."""

    version_number: int
    created_at: datetime
    created_by: str = ""
