"""API Keys endpoints."""

from __future__ import annotations

from datetime import datetime
from typing import TYPE_CHECKING
from uuid import UUID

from vikdata.models.api_key import (
    ApiKeyCreate,
    ApiKeyCreateResponse,
    ApiKeyListResponse,
    ApiKeyRotateResponse,
    ApiKeyUpdateRoles,
    ApiKeyValidateRequest,
    ApiKeyValidateResponse,
    ApiKeyWithRolesResponse,
)

if TYPE_CHECKING:
    from vikdata.client import VikdataClient


class ApiKeysAPI:
    """API Keys API endpoints.

    Handles API key CRUD operations and role assignments.
    """

    def __init__(self, client: "VikdataClient") -> None:
        """Initialize API keys API.

        Args:
            client: VikdataClient instance
        """
        self._client = client

    async def list(self, include_revoked: bool = False) -> ApiKeyListResponse:
        """List all API keys for the current tenant.

        Args:
            include_revoked: Whether to include revoked keys (default: False)

        Returns:
            ApiKeyListResponse with list of API keys

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:read' permission
        """
        params = {"include_revoked": include_revoked}
        return await self._client.request(
            "GET",
            "/api/v1/api-keys",
            params=params,
            response_model=ApiKeyListResponse,
        )

    async def create(
        self,
        name: str,
        role_ids: list[UUID],
        description: str | None = None,
        expires_at: datetime | None = None,
    ) -> ApiKeyCreateResponse:
        """Create a new API key with role-based permissions.

        The full key is only returned ONCE on creation. Store it securely.

        Args:
            name: Key name
            role_ids: List of role IDs to assign (determines permissions)
            description: Optional description
            expires_at: Optional expiration timestamp

        Returns:
            ApiKeyCreateResponse with full key (only shown once)

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:write' permission
            ValidationError: Invalid input data
            ResourceNotFoundError: Role not found
        """
        request = ApiKeyCreate(
            name=name,
            description=description,
            role_ids=role_ids,
            expires_at=expires_at,
        )
        return await self._client.request(
            "POST",
            "/api/v1/api-keys",
            json=request,
            response_model=ApiKeyCreateResponse,
        )

    async def get(self, key_id: UUID) -> ApiKeyWithRolesResponse:
        """Get an API key by ID.

        The full key is never returned after creation.

        Args:
            key_id: API key ID

        Returns:
            ApiKeyWithRolesResponse with key details

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:read' permission
            ResourceNotFoundError: API key not found
        """
        return await self._client.request(
            "GET",
            f"/api/v1/api-keys/{key_id}",
            response_model=ApiKeyWithRolesResponse,
        )

    async def update_roles(
        self,
        key_id: UUID,
        role_ids: list[UUID],
    ) -> ApiKeyWithRolesResponse:
        """Update the roles assigned to an API key.

        This replaces all existing role assignments with the new ones.

        Args:
            key_id: API key ID
            role_ids: New list of role IDs

        Returns:
            ApiKeyWithRolesResponse with updated key

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:write' permission
            ResourceNotFoundError: API key or role not found
        """
        request = ApiKeyUpdateRoles(role_ids=role_ids)
        return await self._client.request(
            "PATCH",
            f"/api/v1/api-keys/{key_id}/roles",
            json=request,
            response_model=ApiKeyWithRolesResponse,
        )

    async def revoke(self, key_id: UUID) -> None:
        """Revoke an API key.

        Revoked keys cannot be used for authentication.

        Args:
            key_id: API key ID

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:delete' permission
            ResourceNotFoundError: API key not found
        """
        await self._client.request(
            "DELETE",
            f"/api/v1/api-keys/{key_id}",
        )

    async def rotate(self, key_id: UUID) -> ApiKeyRotateResponse:
        """Rotate an API key.

        Creates a new key with the same properties and roles, revokes the old one.
        The new key is only returned ONCE on rotation. Store it securely.

        Args:
            key_id: API key ID to rotate

        Returns:
            ApiKeyRotateResponse with new key (only shown once)

        Raises:
            AuthenticationError: Not authenticated
            AuthorizationError: Missing 'api-keys:write' permission
            ResourceNotFoundError: API key not found
        """
        return await self._client.request(
            "POST",
            f"/api/v1/api-keys/{key_id}/rotate",
            response_model=ApiKeyRotateResponse,
        )

    async def validate(self, api_key: str) -> ApiKeyValidateResponse:
        """Validate an API key via the internal service-to-service endpoint.

        Uses X-Service-Token header for authentication. The service token
        is the client's api_key (set during initialization).

        This is used by services (fishinfo, ingress cores) to validate
        incoming API keys from external clients.

        Args:
            api_key: The full API key to validate

        Returns:
            ApiKeyValidateResponse with key details, permissions, and superadmin flag

        Raises:
            AuthenticationError: API key is invalid or inactive
        """
        request = ApiKeyValidateRequest(api_key=api_key)
        return await self._client.request(
            "POST",
            "/api/v1/internal/validate-key",
            json=request,
            headers={"X-Service-Token": self._client.api_key or ""},
            response_model=ApiKeyValidateResponse,
        )
