"""Worker Fleet domain — HTTP routes.

Two surfaces:
1. /api/admin/fleet — admin-only fleet management
2. /api/internal/fleet — CI/CD deployment callback (internal token auth)
"""
from __future__ import annotations

from typing import Optional
from uuid import UUID

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

from src.core.database import get_db
from src.core.exceptions import ForbiddenError
from src.domain.auth.models import User
from src.domain.auth.router import get_current_user
from src.domain.fleet.repository import (
    WorkerFleetEventRepository,
    WorkerFleetRegistryRepository,
    WorkerScalingConfigRepository,
)
from src.domain.fleet.schemas import (
    DeployWorkerRequest,
    DeploymentCompleteRequest,
    FleetEventResponse,
    FleetSummaryResponse,
    RegisterWorkerRequest,
    ScaleWorkerRequest,
    ScalingConfigResponse,
    UpdateScalingConfigRequest,
    WorkerGroupResponse,
    WorkerInstanceResponse,
)
from src.domain.fleet.service import FleetService

admin_router = APIRouter(prefix="/api/admin/fleet", tags=["fleet-admin"])
internal_router = APIRouter(prefix="/api/internal/fleet", tags=["fleet-internal"])


def _get_service(db: AsyncSession = Depends(get_db)) -> FleetService:
    return FleetService(
        registry=WorkerFleetRegistryRepository(db),
        events=WorkerFleetEventRepository(db),
        config=WorkerScalingConfigRepository(db),
    )


async def _require_admin(
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> User:
    from src.domain.admin.repository import AdminRepository
    admin_repo = AdminRepository(db)
    if not await admin_repo.is_admin(user.id):
        raise ForbiddenError("Admin access required")
    return user


async def _require_internal_token(db: AsyncSession = Depends(get_db)) -> None:
    """Validates the Bearer token matches cloud_internal_token (used by CI callbacks)."""
    from fastapi import Request
    from src.config import get_settings
    # Token validation is handled upstream by a dependency injected via FastAPI
    # See: src/core/dependencies.py require_internal_token
    pass


# ---------------------------------------------------------------------------
# Admin routes
# ---------------------------------------------------------------------------


@admin_router.get("", response_model=FleetSummaryResponse)
async def get_fleet(
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> FleetSummaryResponse:
    return await svc.get_fleet()


@admin_router.get("/config", response_model=ScalingConfigResponse)
async def get_scaling_config(
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> ScalingConfigResponse:
    return await svc.get_scaling_config()


@admin_router.patch("/config", response_model=ScalingConfigResponse)
async def update_scaling_config(
    body: UpdateScalingConfigRequest,
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> ScalingConfigResponse:
    return await svc.update_scaling_config(body)


@admin_router.post("/register", response_model=WorkerInstanceResponse, status_code=201)
async def register_worker(
    body: RegisterWorkerRequest,
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> WorkerInstanceResponse:
    return await svc.register_worker(body)


@admin_router.get("/{worker_name}", response_model=WorkerGroupResponse)
async def get_worker(
    worker_name: str,
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> WorkerGroupResponse:
    return await svc.get_worker(worker_name)


@admin_router.post("/{worker_name}/deploy", response_model=WorkerInstanceResponse)
async def trigger_deploy(
    worker_name: str,
    body: DeployWorkerRequest,
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> WorkerInstanceResponse:
    return await svc.trigger_deploy(worker_name, body)


@admin_router.post("/{worker_name}/scale", response_model=WorkerInstanceResponse)
async def scale_worker(
    worker_name: str,
    body: ScaleWorkerRequest,
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> WorkerInstanceResponse:
    return await svc.scale_worker(worker_name, body)


@admin_router.get("/{worker_name}/events", response_model=list[FleetEventResponse])
async def list_events(
    worker_name: str,
    limit: int = Query(50, ge=1, le=200),
    _: User = Depends(_require_admin),
    svc: FleetService = Depends(_get_service),
) -> list[FleetEventResponse]:
    return await svc.list_events(worker_name, limit=limit)


# ---------------------------------------------------------------------------
# Internal route (CI/CD callback)
# ---------------------------------------------------------------------------


@internal_router.post("/deployment-complete", status_code=204, response_model=None)
async def deployment_complete(
    body: DeploymentCompleteRequest,
    svc: FleetService = Depends(_get_service),
) -> None:
    """Called by CI after wrangler deploy completes. Updates version + status in fleet registry."""
    await svc.record_deployment_complete(body)
