"""REST API for the service registry.

Service instances hold non-secret config and encrypted secrets. Plaintext
secrets are never returned; only the boolean ``secrets_set`` map is exposed.
"""

from __future__ import annotations

import logging
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status

from media_library_viewer_api.dependencies import get_settings_store
from media_library_viewer_api.integrations.base import validate_config
from media_library_viewer_api.integrations.registry import (
    SERVICE_DEFINITIONS,
    get_service_definition,
    require_service_definition,
)
from media_library_viewer_api.models.services import (
    SecretFieldInfo,
    ServiceInstance,
    ServiceInstanceInput,
    ServiceTypeInfo,
    WidgetKindInfo,
)
from media_library_viewer_api.services.settings_store import SettingsStore

router = APIRouter(prefix="/api/services", tags=["services"])

logger = logging.getLogger(__name__)


def _to_type_info(service_type: str) -> ServiceTypeInfo:
    definition = require_service_definition(service_type)
    return ServiceTypeInfo(
        service_type=definition.service_type,
        name=definition.name,
        description=definition.description,
        config_schema=definition.config_schema,
        secret_fields=[
            SecretFieldInfo(
                key=sf.key,
                label=sf.label,
                required=sf.required,
                helper=sf.helper,
            )
            for sf in definition.secret_fields
        ],
        widget_kinds=[
            WidgetKindInfo(
                kind=wk.kind,
                name=wk.name,
                description=wk.description,
                config_schema=wk.config_schema,
                default_config=wk.default_config,
                refresh_interval_ms=wk.refresh_interval_ms,
            )
            for wk in definition.widget_kinds
        ],
    )


def _to_instance(row: dict[str, Any]) -> ServiceInstance:
    """Build an API response model, surfacing only secret 'set' flags."""
    definition = get_service_definition(row["service_type"])
    known_secrets = definition.secret_keys if definition else set()
    secrets_blob = row.get("secrets") or {}
    secrets_set = {key: (key in secrets_blob and bool(secrets_blob[key])) for key in known_secrets}
    return ServiceInstance(
        id=row["id"],
        service_type=row["service_type"],
        name=row["name"],
        config=row.get("config") or {},
        secrets_set=secrets_set,
        enabled=row["enabled"],
        created_at=row["created_at"],
        updated_at=row["updated_at"],
    )


def _validate_input(body: ServiceInstanceInput) -> None:
    """Validate service_type, config, and secret keys against the definition."""
    definition = get_service_definition(body.service_type)
    if definition is None:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
            detail=f"Unknown service type: {body.service_type}",
        )
    try:
        validate_config(definition.config_model, body.config)
    except Exception as exc:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
            detail=f"Invalid service config: {exc}",
        ) from exc
    unknown_secrets = set(body.secrets) - definition.secret_keys
    if unknown_secrets:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
            detail=f"Unknown secret fields for {body.service_type}: {sorted(unknown_secrets)}",
        )


@router.get("/types")
def list_types() -> list[ServiceTypeInfo]:
    """Return metadata for every registered service type."""
    return [_to_type_info(service_type) for service_type in sorted(SERVICE_DEFINITIONS)]


@router.get("/instances")
def list_instances(
    service_type: str | None = None,
    store: SettingsStore = Depends(get_settings_store),
) -> list[ServiceInstance]:
    """Return all persisted service instances (no plaintext secrets)."""
    rows = store.list_services(service_type)
    return [_to_instance(row) for row in rows]


@router.post("/instances", status_code=status.HTTP_201_CREATED)
def create_instance(
    body: ServiceInstanceInput,
    store: SettingsStore = Depends(get_settings_store),
) -> ServiceInstance:
    """Create a new service instance."""
    _validate_input(body)
    row = store.upsert_service(
        {
            "id": body.id,
            "service_type": body.service_type,
            "name": body.name,
            "config": body.config,
            "enabled": body.enabled,
        },
        secret_values=body.secrets,
    )
    return _to_instance(row)


@router.put("/instances/{service_id}")
def update_instance(
    service_id: str,
    body: ServiceInstanceInput,
    store: SettingsStore = Depends(get_settings_store),
) -> ServiceInstance:
    """Update an existing service instance."""
    existing = store.get_service(service_id)
    if not existing:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Service not found")
    if body.id is not None and body.id != service_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="ID in path does not match ID in body",
        )
    _validate_input(body)
    row = store.upsert_service(
        {
            "id": service_id,
            "service_type": body.service_type,
            "name": body.name,
            "config": body.config,
            "enabled": body.enabled,
        },
        secret_values=body.secrets,
        service_id=service_id,
    )
    return _to_instance(row)


@router.delete("/instances/{service_id}")
def delete_instance(
    service_id: str,
    store: SettingsStore = Depends(get_settings_store),
) -> dict[str, str]:
    """Delete a service instance (cascade-deletes widgets referencing it)."""
    existing = store.get_service(service_id)
    if not existing:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Service not found")
    store.delete_service(service_id)
    return {"status": "deleted"}
