"""FastAPI router factory for the secrets HTTP API."""

from __future__ import annotations

from fastapi import APIRouter, HTTPException

from vault.config import get_secrets
from vault.models import (
    AccessPolicy,
    SecretCreateRequest,
    SecretMetadataResponse,
    SecretResponse,
    SecretUpdateRequest,
    SecretVersionResponse,
)
from errors import AuthorizationError, BusinessLogicError, ConflictError, NotFoundError, ValidationError
from api_core.responses import ApiResponse, PaginatedResponse


def create_secrets_router(*, prefix: str = "/secrets", tags: list[str] | None = None) -> APIRouter:
    """Build and return a FastAPI router with full secrets CRUD + rotation."""

    router = APIRouter(prefix=prefix, tags=tags or ["secrets"])

    @router.get("", response_model=list[SecretMetadataResponse])
    async def list_secrets() -> list[SecretMetadataResponse]:
        container = get_secrets()
        metas = await container.store.list_secrets()
        return [
            SecretMetadataResponse(
                name=m.name,
                version=m.version,
                tags=m.tags,
                created_at=m.created_at,
                updated_at=m.updated_at,
                expires_at=m.expires_at,
            )
            for m in metas
        ]

    @router.post("", response_model=SecretMetadataResponse, status_code=201)
    async def create_secret(body: SecretCreateRequest) -> SecretMetadataResponse:
        container = get_secrets()
        existing = await container.store.get_secret(body.name)
        if existing is not None:
            raise ConflictError(f"Secret '{body.name}' already exists")
        policy = AccessPolicy(
            allowed_services=body.allowed_services,
            allowed_roles=body.allowed_roles,
        )
        secret = await container.store.set_secret(
            body.name,
            body.value,
            tags=body.tags,
            expires_at=body.expires_at,
            access_policy=policy,
        )
        return SecretMetadataResponse(
            name=secret.name,
            version=secret.version,
            tags=secret.tags,
            created_at=secret.created_at,
            updated_at=secret.updated_at,
            expires_at=secret.expires_at,
        )

    @router.get("/{name}", response_model=SecretResponse)
    async def get_secret(name: str) -> SecretResponse:
        container = get_secrets()
        secret = await container.store.get_secret(name)
        if secret is None:
            raise NotFoundError(f"Secret '{name}' not found")
        value = container.encryption.decrypt(secret.encrypted_value).decode()
        return SecretResponse(
            name=secret.name,
            value=value,
            version=secret.version,
            tags=secret.tags,
            created_at=secret.created_at,
            updated_at=secret.updated_at,
            expires_at=secret.expires_at,
        )

    @router.put("/{name}", response_model=SecretMetadataResponse)
    async def update_secret(name: str, body: SecretUpdateRequest) -> SecretMetadataResponse:
        container = get_secrets()
        rotated = await container.store.rotate(name, body.value)
        if rotated is None:
            raise NotFoundError(f"Secret '{name}' not found")
        if body.tags is not None:
            rotated.tags = body.tags
        return SecretMetadataResponse(
            name=rotated.name,
            version=rotated.version,
            tags=rotated.tags,
            created_at=rotated.created_at,
            updated_at=rotated.updated_at,
            expires_at=rotated.expires_at,
        )

    @router.delete("/{name}", status_code=204)
    async def delete_secret(name: str) -> None:
        container = get_secrets()
        deleted = await container.store.delete_secret(name)
        if not deleted:
            raise NotFoundError(f"Secret '{name}' not found")

    @router.get("/{name}/versions", response_model=list[SecretVersionResponse])
    async def list_versions(name: str) -> list[SecretVersionResponse]:
        container = get_secrets()
        versions = await container.store.get_versions(name)
        if not versions:
            raise NotFoundError(f"Secret '{name}' not found")
        return [
            SecretVersionResponse(
                version_number=v.version_number,
                created_at=v.created_at,
                created_by=v.created_by,
            )
            for v in versions
        ]

    @router.post("/{name}/rotate", response_model=SecretMetadataResponse)
    async def rotate_secret(name: str, body: SecretUpdateRequest) -> SecretMetadataResponse:
        container = get_secrets()
        rotated = await container.store.rotate(name, body.value, created_by="manual-rotation")
        if rotated is None:
            raise NotFoundError(f"Secret '{name}' not found")
        return SecretMetadataResponse(
            name=rotated.name,
            version=rotated.version,
            tags=rotated.tags,
            created_at=rotated.created_at,
            updated_at=rotated.updated_at,
            expires_at=rotated.expires_at,
        )

    return router
