"""Connections resource -- user connections and OAuth flow initiation."""

from __future__ import annotations

import builtins
from typing import Any
from uuid import UUID

from mcpgateway_sdk._http import HTTPClient
from mcpgateway_sdk.models.connection import (
    BasicConnection,
    Connection,
    ConnectionCreated,
    OAuthAuthorization,
)

_ENDPOINTS = {
    "create": ("POST", "/api/v1/connections"),
    "create_basic": ("POST", "/api/v1/connections/basic"),
    "list": ("GET", "/api/v1/connections"),
    "get": ("GET", "/api/v1/connections/{connection_id}"),
    "revoke": ("DELETE", "/api/v1/connections/{connection_id}"),
    "refresh": ("POST", "/api/v1/connections/{connection_id}/refresh"),
    "initiate_oauth": ("POST", "/api/v1/servers/{server_id}/oauth/authorize"),
}


class ConnectionsResource:
    """Manage user connections (API key, Basic auth, OAuth) to MCP servers."""

    _endpoints = _ENDPOINTS

    def __init__(self, http: HTTPClient) -> None:
        self._http = http

    # ── CRUD ──────────────────────────────────────────────────────────

    async def create(
        self,
        server_id: str | UUID,
        credential_type: str,
        credential_value: str,
        *,
        alias: str | None = None,
        header_name: str = "Authorization",
        prefix: str = "",
    ) -> ConnectionCreated:
        """Create an API key or bearer token connection.

        Args:
            server_id: UUID of the MCP server to connect to.
            credential_type: Type of credential: ``"api_key"`` or ``"bearer"``.
                Use ``create_basic()`` for HTTP Basic auth.
            credential_value: The credential value (encrypted before storage).
            alias: Optional friendly name for this connection.
            header_name: HTTP header name (default ``"Authorization"``).
            prefix: Prefix for the credential value (e.g. ``"Bearer "``).

        Returns:
            A ConnectionCreated with masked credential info.
        """
        body: dict[str, Any] = {
            "server_id": str(server_id),
            "credential_type": credential_type,
            "credential_value": credential_value,
            "header_name": header_name,
            "prefix": prefix,
        }
        if alias is not None:
            body["alias"] = alias
        data = await self._http.request("POST", "/api/v1/connections", json=body)
        return ConnectionCreated.model_validate(data)

    async def create_basic(
        self,
        server_id: str | UUID,
        username: str,
        password: str,
        *,
        connection_data: dict[str, Any] | None = None,
    ) -> BasicConnection:
        """Create an HTTP Basic auth connection.

        Args:
            server_id: UUID of the MCP server to connect to.
            username: HTTP Basic auth username.
            password: HTTP Basic auth password (encrypted before storage).
            connection_data: Optional non-credential config (server URLs, etc.).

        Returns:
            A BasicConnection with username visible, password never exposed.
        """
        body: dict[str, Any] = {
            "server_id": str(server_id),
            "username": username,
            "password": password,
        }
        if connection_data is not None:
            body["connection_data"] = connection_data
        data = await self._http.request("POST", "/api/v1/connections/basic", json=body)
        return BasicConnection.model_validate(data)

    async def list(
        self,
        *,
        include_server: bool = False,
        include_revoked: bool = False,
    ) -> builtins.list[Connection]:
        """List the current user's connections.

        Args:
            include_server: Include server info in response.
            include_revoked: Include revoked connections.

        Returns:
            A list of Connection objects.
        """
        params: dict[str, Any] = {
            "include_server": include_server,
            "include_revoked": include_revoked,
        }
        data = await self._http.request("GET", "/api/v1/connections", params=params)
        return [Connection.model_validate(item) for item in data.get("items", [])]

    async def get(self, connection_id: str | UUID) -> Connection:
        """Get a specific connection.

        Args:
            connection_id: UUID of the connection.

        Returns:
            A Connection with full details (tokens never exposed).
        """
        data = await self._http.request("GET", f"/api/v1/connections/{connection_id}")
        return Connection.model_validate(data)

    async def revoke(self, connection_id: str | UUID) -> None:
        """Revoke a connection.

        Args:
            connection_id: UUID of the connection to revoke.
        """
        await self._http.request("DELETE", f"/api/v1/connections/{connection_id}")

    async def refresh(self, connection_id: str | UUID) -> Connection:
        """Force-refresh an OAuth token.

        Args:
            connection_id: UUID of the connection to refresh.

        Returns:
            The refreshed Connection with updated token metadata.
        """
        data = await self._http.request("POST", f"/api/v1/connections/{connection_id}/refresh")
        return Connection.model_validate(data)

    # ── OAuth flow ────────────────────────────────────────────────────

    async def initiate_oauth(
        self,
        server_id: str | UUID,
        oauth_app_id: str | UUID,
        *,
        redirect_uri: str | None = None,
        scopes: builtins.list[str] | None = None,
        connection_data: dict[str, Any] | None = None,
    ) -> OAuthAuthorization:
        """Initiate an OAuth flow for a server.

        Args:
            server_id: UUID of the MCP server.
            oauth_app_id: UUID of the OAuth app to use.
            redirect_uri: Where to redirect after OAuth completes.
            scopes: Override default scopes (optional).
            connection_data: Non-credential config to preserve through the flow.

        Returns:
            An OAuthAuthorization with the authorization URL and state token.
        """
        body: dict[str, Any] = {"oauth_app_id": str(oauth_app_id)}
        if redirect_uri is not None:
            body["redirect_uri"] = redirect_uri
        if scopes is not None:
            body["scopes"] = scopes
        if connection_data is not None:
            body["connection_data"] = connection_data
        data = await self._http.request(
            "POST",
            f"/api/v1/servers/{server_id}/oauth/authorize",
            json=body,
        )
        return OAuthAuthorization.model_validate(data)
