"""
API endpoints for the database configuration wizard and migration tool.

Provides REST endpoints for:
- Testing database connections
- Building connection strings from form components
- Previewing and executing data migrations between databases
"""

import logging

from fastapi import APIRouter, HTTPException, Request, status
from pydantic import BaseModel, Field

from app.utils.db_migrate import migrate_data, preview_migration
from app.utils.db_wizard import (
    build_connection_string,
    get_supported_backends,
    parse_connection_string,
    test_connection,
    validate_url_format,
)

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/database", tags=["database"])


def _require_admin(request: Request) -> dict:
    """Ensure the caller is an admin.  Raises 403 otherwise."""
    user = request.session.get("user")
    if not user or not user.get("is_admin"):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required")
    return user


# ---------------------------------------------------------------------------
# Request / Response models
# ---------------------------------------------------------------------------


class ConnectionStringRequest(BaseModel):
    """Request body for building a connection string."""

    backend: str = Field(..., description="Database backend: sqlite, postgresql, mysql")
    host: str = Field("", description="Database server hostname")
    port: int | None = Field(None, description="Database server port")
    database: str = Field("", description="Database name")
    username: str = Field("", description="Authentication username")
    password: str = Field("", description="Authentication password")
    ssl_mode: str = Field("", description="SSL mode (e.g. require, verify-full)")
    extra_options: str = Field("", description="Additional query-string options")
    sqlite_path: str = Field("", description="File path for SQLite databases")


class TestConnectionRequest(BaseModel):
    """Request body for testing a database connection."""

    url: str = Field(..., description="Full SQLAlchemy connection URL to test")


class MigrateRequest(BaseModel):
    """Request body for data migration."""

    source_url: str = Field(..., description="Source database connection URL")
    target_url: str = Field(..., description="Target database connection URL")


# ---------------------------------------------------------------------------
# Endpoints
# ---------------------------------------------------------------------------


@router.get("/backends")
async def list_backends() -> list[dict]:
    """List all supported database backends with metadata."""
    return get_supported_backends()


@router.post("/build-url")
async def build_url(body: ConnectionStringRequest, request: Request) -> dict:
    """Build a SQLAlchemy connection string from individual components.

    Returns the assembled URL string.
    """
    _require_admin(request)
    try:
        url = build_connection_string(
            backend=body.backend,
            host=body.host,
            port=body.port,
            database=body.database,
            username=body.username,
            password=body.password,
            ssl_mode=body.ssl_mode,
            extra_options=body.extra_options,
            sqlite_path=body.sqlite_path,
        )
        return {"url": url}
    except ValueError as exc:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc


@router.post("/parse-url")
async def parse_url(body: TestConnectionRequest, request: Request) -> dict:
    """Parse a connection string into its components."""
    _require_admin(request)
    return parse_connection_string(body.url)


@router.post("/validate-url")
async def validate_url(body: TestConnectionRequest, request: Request) -> dict:
    """Validate a connection string format without connecting."""
    _require_admin(request)
    return validate_url_format(body.url)


@router.post("/test-connection")
async def test_db_connection(body: TestConnectionRequest, request: Request) -> dict:
    """Test connectivity to a database and return status info.

    This creates a temporary engine, executes ``SELECT 1``, and disposes
    of the engine.  It does **not** modify any global application state.
    """
    _require_admin(request)
    return test_connection(body.url)


@router.post("/preview-migration")
async def preview_db_migration(body: TestConnectionRequest, request: Request) -> dict:
    """Preview what a migration from the given source would include.

    Returns a table-by-table row count without actually copying data.
    """
    _require_admin(request)
    return preview_migration(body.url)


@router.post("/migrate")
async def execute_migration(body: MigrateRequest, request: Request) -> dict:
    """Execute a full data migration from source to target database.

    **Warning:** This copies all data from the source database into the
    target.  The target schema is created from the current application
    models.  Existing data in the target is **not** deleted first — use
    on an empty target database.
    """
    _require_admin(request)

    # Validate both URLs first
    src_check = validate_url_format(body.source_url)
    if not src_check.get("valid"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid source URL: {src_check.get('error', 'unknown')}",
        )
    tgt_check = validate_url_format(body.target_url)
    if not tgt_check.get("valid"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid target URL: {tgt_check.get('error', 'unknown')}",
        )

    result = migrate_data(body.source_url, body.target_url)
    if not result["success"]:
        error_summary = "; ".join(result.get("errors", ["Unknown error"]))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Migration completed with errors: {error_summary}",
        )
    return result
