"""Authentication endpoints."""

from typing import NotRequired, TypedDict, Unpack, final

from pydantic import TypeAdapter

from ksef2.core import headers, routes
from ksef2.endpoints.base import BaseEndpoints
from ksef2.infra.schema.api import spec
from ksef2.infra.schema.api.supp.auth import InitTokenAuthenticationRequest

AuthSessionsQueryParams = TypedDict(
    "AuthSessionsQueryParams",
    {
        "pageSize": NotRequired[int | None],
    },
)

XadesAuthParams = TypedDict(
    "XadesAuthParams",
    {
        "verifyCertificateChain": NotRequired[str | None],
    },
)


@final
class AuthEndpoints(BaseEndpoints):
    """Raw authentication endpoints backed by generated schema models."""

    _AUTH_SESSIONS_PARAMS = TypeAdapter(AuthSessionsQueryParams)

    def list_sessions(
        self,
        continuation_token: str | None = None,
        **params: Unpack[AuthSessionsQueryParams],
    ) -> spec.AuthenticationListResponse:
        """Fetch one page of authentication sessions."""
        req_headers = (
            {"x-continuation-token": continuation_token} if continuation_token else None
        )

        return self._parse(
            self._transport.get(
                path=routes.AuthRoutes.LIST_SESSIONS,
                params=self.build_params(params, self._AUTH_SESSIONS_PARAMS),
                headers=req_headers,
            ),
            spec.AuthenticationListResponse,
        )

    _XADES_AUTH_PARAMS = TypeAdapter(XadesAuthParams)

    def xades_auth(
        self,
        signed_xml: bytes,
        verify_chain: bool = False,
    ) -> spec.AuthenticationInitResponse:
        """Start authentication from an XAdES-signed XML payload."""

        query_params: XadesAuthParams = {
            "verifyCertificateChain": str(verify_chain).lower(),
        }
        return self._parse(
            self._transport.request(
                "POST",
                routes.AuthRoutes.XADES_SIGNATURE,
                params=self.build_params(query_params, self._XADES_AUTH_PARAMS),
                content=signed_xml,
                headers={"Content-Type": "application/xml"},
            ),
            spec.AuthenticationInitResponse,
        )

    def challenge(self) -> spec.AuthenticationChallengeResponse:
        """Create an authentication challenge."""
        return self._parse(
            self._transport.post(
                path=routes.AuthRoutes.CHALLENGE,
            ),
            spec.AuthenticationChallengeResponse,
        )

    def token_auth(
        self, body: InitTokenAuthenticationRequest
    ) -> spec.AuthenticationInitResponse:
        """Start token-based authentication."""
        return self._parse(
            self._transport.post(
                path=routes.AuthRoutes.TOKEN_AUTH,
                json=body.model_dump(mode="json", by_alias=True),
            ),
            spec.AuthenticationInitResponse,
        )

    def auth_status(
        self,
        bearer_token: str,
        reference_number: str,
    ) -> spec.AuthenticationOperationStatusResponse:
        """Fetch the status of an in-progress authentication operation."""
        return self._parse(
            self._transport.get(
                path=routes.AuthRoutes.AUTH_STATUS.format(
                    referenceNumber=reference_number
                ),
                headers=headers.KSeFHeaders.bearer(bearer_token),
            ),
            spec.AuthenticationOperationStatusResponse,
        )

    def redeem_token(self, bearer_token: str) -> spec.AuthenticationTokensResponse:
        """Redeem a temporary authentication token for access and refresh tokens."""
        return self._parse(
            self._transport.post(
                path=routes.AuthRoutes.REDEEM_TOKEN,
                headers=headers.KSeFHeaders.bearer(bearer_token),
            ),
            spec.AuthenticationTokensResponse,
        )

    def refresh_token(
        self, bearer_token: str
    ) -> spec.AuthenticationTokenRefreshResponse:
        """Refresh an access token using a refresh token bearer header."""
        return self._parse(
            self._transport.post(
                path=routes.AuthRoutes.REFRESH_TOKEN,
                headers=headers.KSeFHeaders.bearer(bearer_token),
            ),
            spec.AuthenticationTokenRefreshResponse,
        )

    def terminate_current_session(self) -> None:
        """Terminate the current authentication session."""
        _ = self._transport.delete(
            path=routes.AuthRoutes.TERMINATE_CURRENT_SESSION,
        )

    def terminate_auth_session(self, reference_number: str) -> None:
        """Terminate an authentication session by reference number."""
        _ = self._transport.delete(
            path=routes.AuthRoutes.TERMINATE_AUTH_SESSION.format(
                referenceNumber=reference_number
            ),
        )
