"""External Connections domain — request/response schemas."""
from __future__ import annotations

from datetime import datetime
from typing import Any, Optional
from uuid import UUID

from pydantic import BaseModel, field_validator


class CreateSQLConnectionRequest(BaseModel):
    name: str
    type: str  # "postgres" | "mysql"
    host: str
    port: int
    database: str
    username: str
    password: str
    ssl_mode: str = "require"
    max_rows_per_query: int = 1000
    readonly: bool = False

    @field_validator("type")
    @classmethod
    def validate_sql_type(cls, v: str) -> str:
        if v not in ("postgres", "mysql"):
            raise ValueError("type must be 'postgres' or 'mysql' for SQL connections")
        return v

    @field_validator("ssl_mode")
    @classmethod
    def validate_ssl_mode(cls, v: str) -> str:
        if v not in ("require", "prefer", "disable"):
            raise ValueError("ssl_mode must be 'require', 'prefer', or 'disable'")
        return v

    @field_validator("port")
    @classmethod
    def validate_port(cls, v: int) -> int:
        if not 1 <= v <= 65535:
            raise ValueError("port must be between 1 and 65535")
        return v


class CreateHTTPConnectionRequest(BaseModel):
    name: str
    type: str = "http_api"
    http_base_url: str
    http_auth_type: str
    http_auth_secret: Optional[str] = None
    http_default_headers: Optional[dict[str, str]] = None
    max_response_size_bytes: Optional[int] = None
    readonly: bool = False

    @field_validator("http_auth_type")
    @classmethod
    def validate_auth_type(cls, v: str) -> str:
        if v not in ("api_key", "bearer", "basic", "oauth2_client", "none"):
            raise ValueError(
                "http_auth_type must be 'api_key', 'bearer', 'basic', 'oauth2_client', or 'none'"
            )
        return v


class CreateConnectionRequest(BaseModel):
    """Polymorphic create — caller sets 'type' to drive field validation."""

    name: str
    type: str
    # SQL fields
    host: Optional[str] = None
    port: Optional[int] = None
    database: Optional[str] = None
    username: Optional[str] = None
    password: Optional[str] = None
    ssl_mode: str = "require"
    max_rows_per_query: int = 1000
    # HTTP API fields
    http_base_url: Optional[str] = None
    http_auth_type: Optional[str] = None
    http_auth_secret: Optional[str] = None
    http_default_headers: Optional[dict[str, str]] = None
    max_response_size_bytes: Optional[int] = None
    # Shared
    readonly: bool = False


class UpdateConnectionRequest(BaseModel):
    """Partial update — all fields optional.  Password/secret re-submission triggers rotation."""

    host: Optional[str] = None
    port: Optional[int] = None
    database: Optional[str] = None
    username: Optional[str] = None
    password: Optional[str] = None
    ssl_mode: Optional[str] = None
    max_rows_per_query: Optional[int] = None
    http_base_url: Optional[str] = None
    http_auth_type: Optional[str] = None
    http_auth_secret: Optional[str] = None
    http_default_headers: Optional[dict[str, str]] = None
    max_response_size_bytes: Optional[int] = None
    readonly: Optional[bool] = None


class ConnectionResponse(BaseModel):
    id: UUID
    project_id: UUID
    workspace_id: UUID
    name: str
    type: str
    status: str
    readonly: bool
    # SQL — opaque hyperdrive ref only (not credentials)
    hyperdrive_id: Optional[str] = None
    ssl_mode: Optional[str] = None
    max_rows_per_query: Optional[int] = None
    host: Optional[str] = None
    port: Optional[int] = None
    database: Optional[str] = None
    username: Optional[str] = None
    # HTTP API — no secret
    http_base_url: Optional[str] = None
    http_auth_type: Optional[str] = None
    http_default_headers: Optional[dict[str, Any]] = None
    max_response_size_bytes: Optional[int] = None
    # Introspection
    schema_snapshot_json: Optional[dict[str, Any]] = None
    schema_snapshot_at: Optional[datetime] = None
    last_tested_at: Optional[datetime] = None
    last_test_error: Optional[str] = None
    created_at: datetime
    updated_at: datetime


class TestConnectionResponse(BaseModel):
    ok: bool
    status: str  # "active" | "error"
    error: Optional[str] = None
    schema_snapshot_json: Optional[dict[str, Any]] = None
    schema_snapshot_at: Optional[datetime] = None


class SchemaSnapshotResponse(BaseModel):
    name: str
    type: str
    schema_snapshot_json: Optional[dict[str, Any]] = None
    schema_snapshot_at: Optional[datetime] = None
