"""Admin API for W4P dispatcher KV routing."""
from typing import Any, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from src.config import get_settings
from src.core.database import get_db
from src.domain.admin.router import require_admin
from src.domain.auth.models import User
from src.domain.hosting.routing_plane import (
    CloudflareAPIError,
    CloudflareRoutingProvider,
    resolve_dispatch_route_project_ref,
)
from src.domain.hosting.schemas import (
    DispatchRouteResponse,
    DispatchRouteUpsert,
)
from src.domain.projects.repository import ProjectRepository

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


def _require_routing_configured() -> None:
    s = get_settings()
    if (s.hosting_provider or "").strip() not in {
        "cloudflare_pages", "cloudflare_w4p", "cloudflare_w4p_static", "w4p"
    }:
        raise HTTPException(
            status_code=503,
            detail="Hosting routing is not configured for the selected hosting provider.",
        )

    if not (s.cloudflare_api_token or "").strip() or not (s.cloudflare_dispatch_kv_namespace_id or "").strip():
        raise HTTPException(
            status_code=503,
            detail="Cloudflare routing is not configured (missing CLOUDFLARE_API_TOKEN or "
            "CLOUDFLARE_DISPATCH_KV_NAMESPACE_ID).",
        )


@router.post("/dispatcher/reconcile")
async def reconcile_dispatcher(admin: User = Depends(require_admin)):
    """Explicitly deploy the shared dispatcher after code/config changes."""
    _require_routing_configured()
    try:
        result = await CloudflareRoutingProvider().deploy_dispatcher()
    except CloudflareAPIError as exc:
        raise HTTPException(status_code=502, detail=str(exc)) from exc
    return {"ok": True, **result}


@router.post("/dispatch-routes", response_model=DispatchRouteResponse)
async def upsert_dispatch_route(
    body: DispatchRouteUpsert,
    admin: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db),
):
    """Create or update a ``host:{hostname}`` KV record for the shared dispatcher Worker.

    The **user Worker script** must already exist in the Workers for Platforms dispatch
    namespace for the chosen environment. This endpoint only updates routing KV (and
    optionally redeploys the dispatcher Worker when ``sync_dispatcher`` is true).
    """
    _require_routing_configured()
    provider = CloudflareRoutingProvider()
    pref = resolve_dispatch_route_project_ref(
        subdomain=body.subdomain,
        script_name=body.script_name,
        environment=body.environment,
        explicit_project_ref=body.project_ref,
    )
    project_id = (body.project_id or "").strip()
    if not project_id:
        proj = await ProjectRepository(db).get_by_project_ref(pref)
        if proj:
            project_id = str(proj.id)
    try:
        result = await provider.upsert_dispatch_route_for_existing_script(
            subdomain=body.subdomain,
            script_name=body.script_name,
            environment=body.environment,
            project_ref=body.project_ref,
            project_id=project_id,
            target_url=body.target_url,
        )
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except CloudflareAPIError as exc:
        raise HTTPException(status_code=502, detail=str(exc)) from exc

    dispatcher_meta: Optional[dict[str, Any]] = None
    if body.sync_dispatcher:
        try:
            dispatcher_meta = await provider.deploy_dispatcher()
        except CloudflareAPIError as exc:
            raise HTTPException(
                status_code=502,
                detail=f"KV updated but dispatcher sync failed: {exc}",
            ) from exc

    return DispatchRouteResponse(
        hostname=result["hostname"],
        kv_key=result["kv_key"],
        script_name=result["script_name"],
        environment=result["environment"],
        project_ref=result["project_ref"],
        project_id=result.get("project_id") or None,
        dispatcher=dispatcher_meta,
    )


@router.delete("/dispatch-routes/{subdomain}")
async def delete_dispatch_route(
    subdomain: str,
    admin: User = Depends(require_admin),
    script_name: Optional[str] = Query(
        None,
        description="Optional; same as upsert — used with environment to resolve project_ref from p2hs-prod-/p2hs-prev- names.",
    ),
    project_ref: Optional[str] = Query(None, description="Must match upsert if you set a custom project_ref"),
    environment: str = Query("production"),
):
    """Remove KV routing for ``{subdomain}.{HOSTING_PUBLIC_APEX}``."""
    _require_routing_configured()
    provider = CloudflareRoutingProvider()
    try:
        await provider.delete_dispatch_route_by_subdomain(
            subdomain,
            project_ref=project_ref,
            script_name=script_name,
            environment=environment,
        )
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except CloudflareAPIError as exc:
        raise HTTPException(status_code=502, detail=str(exc)) from exc
    return {"ok": True}
