"""Training Task Endpoints."""

import logging
from typing import Annotated

from fastapi import APIRouter, HTTPException, Query

from backend.web.core.auth import AdminTokenDep, TrainingTaskRepoDep
from backend.web.schemas.admin import (
    TrainingLogItem,
    TrainingLogsResponse,
    TrainingStatus,
    TrainingTaskCreate,
    TrainingTaskDetailResponse,
    TrainingTaskItem,
    TrainingTaskListResponse,
    TrainingTaskResponse,
    TrainingType,
)
from backend.web.schemas.common import ErrorResponse

from ._utils import _validate_uuid

logger = logging.getLogger(__name__)


def register_task_routes(router: APIRouter) -> None:
    """Register training task endpoints on the router."""

    @router.post(
        "/tasks",
        response_model=TrainingTaskResponse,
        responses={
            400: {"model": ErrorResponse, "description": "Invalid request"},
            401: {"model": ErrorResponse, "description": "Invalid token"},
        },
        summary="Create training task",
        description="Create a new training task.",
    )
    async def create_training_task(
        request: TrainingTaskCreate,
        admin_token: AdminTokenDep,
        tasks: TrainingTaskRepoDep,
    ) -> TrainingTaskResponse:
        """Create a new training task."""
        config_dict = request.config.model_dump() if request.config else {}

        task_id = tasks.create(
            admin_token=admin_token,
            name=request.name,
            task_type=request.task_type.value,
            description=request.description,
            config=config_dict,
            scheduled_at=request.scheduled_at,
            cron_expression=request.cron_expression,
            is_recurring=bool(request.cron_expression),
        )

        return TrainingTaskResponse(
            task_id=task_id,
            status=TrainingStatus.SCHEDULED if request.scheduled_at else TrainingStatus.PENDING,
            message="Training task created successfully",
        )

    @router.get(
        "/tasks",
        response_model=TrainingTaskListResponse,
        responses={
            401: {"model": ErrorResponse, "description": "Invalid token"},
        },
        summary="List training tasks",
        description="List all training tasks.",
    )
    async def list_training_tasks(
        admin_token: AdminTokenDep,
        tasks_repo: TrainingTaskRepoDep,
        status: Annotated[
            str | None,
            Query(description="Filter by status"),
        ] = None,
        limit: Annotated[
            int,
            Query(ge=1, le=100, description="Page size"),
        ] = 20,
        offset: Annotated[
            int,
            Query(ge=0, description="Offset"),
        ] = 0,
    ) -> TrainingTaskListResponse:
        """List training tasks."""
        valid_statuses = ("pending", "scheduled", "running", "completed", "failed", "cancelled")
        if status and status not in valid_statuses:
            raise HTTPException(
                status_code=400,
                detail=f"Invalid status: {status}. Must be one of: {', '.join(valid_statuses)}",
            )

        task_list, total = tasks_repo.get_paginated(
            admin_token=admin_token,
            status=status,
            limit=limit,
            offset=offset,
        )

        items = [
            TrainingTaskItem(
                task_id=str(task.task_id),
                name=task.name,
                task_type=TrainingType(task.task_type),
                status=TrainingStatus(task.status),
                scheduled_at=task.scheduled_at,
                is_recurring=task.is_recurring,
                started_at=task.started_at,
                completed_at=task.completed_at,
                created_at=task.created_at,
            )
            for task in task_list
        ]

        return TrainingTaskListResponse(
            total=total,
            limit=limit,
            offset=offset,
            tasks=items,
        )

    @router.get(
        "/tasks/{task_id}",
        response_model=TrainingTaskDetailResponse,
        responses={
            401: {"model": ErrorResponse, "description": "Invalid token"},
            404: {"model": ErrorResponse, "description": "Task not found"},
        },
        summary="Get training task detail",
        description="Get training task details.",
    )
    async def get_training_task(
        task_id: str,
        admin_token: AdminTokenDep,
        tasks: TrainingTaskRepoDep,
    ) -> TrainingTaskDetailResponse:
        """Get training task details."""
        _validate_uuid(task_id, "task_id")

        task = tasks.get_by_token(task_id, admin_token)
        if task is None:
            raise HTTPException(
                status_code=404,
                detail="Training task not found or does not belong to this token",
            )

        return TrainingTaskDetailResponse(
            task_id=str(task.task_id),
            name=task.name,
            description=task.description,
            task_type=TrainingType(task.task_type),
            status=TrainingStatus(task.status),
            config=task.config,
            scheduled_at=task.scheduled_at,
            cron_expression=task.cron_expression,
            is_recurring=task.is_recurring,
            started_at=task.started_at,
            completed_at=task.completed_at,
            error_message=task.error_message,
            result_metrics=task.result_metrics,
            model_path=task.model_path,
            created_at=task.created_at,
        )

    @router.post(
        "/tasks/{task_id}/cancel",
        response_model=TrainingTaskResponse,
        responses={
            401: {"model": ErrorResponse, "description": "Invalid token"},
            404: {"model": ErrorResponse, "description": "Task not found"},
            409: {"model": ErrorResponse, "description": "Cannot cancel task"},
        },
        summary="Cancel training task",
        description="Cancel a pending or scheduled training task.",
    )
    async def cancel_training_task(
        task_id: str,
        admin_token: AdminTokenDep,
        tasks: TrainingTaskRepoDep,
    ) -> TrainingTaskResponse:
        """Cancel a training task."""
        _validate_uuid(task_id, "task_id")

        task = tasks.get_by_token(task_id, admin_token)
        if task is None:
            raise HTTPException(
                status_code=404,
                detail="Training task not found or does not belong to this token",
            )

        if task.status not in ("pending", "scheduled"):
            raise HTTPException(
                status_code=409,
                detail=f"Cannot cancel task with status: {task.status}",
            )

        success = tasks.cancel(task_id)
        if not success:
            raise HTTPException(
                status_code=500,
                detail="Failed to cancel training task",
            )

        return TrainingTaskResponse(
            task_id=task_id,
            status=TrainingStatus.CANCELLED,
            message="Training task cancelled successfully",
        )

    @router.get(
        "/tasks/{task_id}/logs",
        response_model=TrainingLogsResponse,
        responses={
            401: {"model": ErrorResponse, "description": "Invalid token"},
            404: {"model": ErrorResponse, "description": "Task not found"},
        },
        summary="Get training logs",
        description="Get training task logs.",
    )
    async def get_training_logs(
        task_id: str,
        admin_token: AdminTokenDep,
        tasks: TrainingTaskRepoDep,
        limit: Annotated[
            int,
            Query(ge=1, le=500, description="Maximum logs to return"),
        ] = 100,
        offset: Annotated[
            int,
            Query(ge=0, description="Offset"),
        ] = 0,
    ) -> TrainingLogsResponse:
        """Get training logs."""
        _validate_uuid(task_id, "task_id")

        task = tasks.get_by_token(task_id, admin_token)
        if task is None:
            raise HTTPException(
                status_code=404,
                detail="Training task not found or does not belong to this token",
            )

        logs = tasks.get_logs(task_id, limit, offset)

        items = [
            TrainingLogItem(
                level=log.level,
                message=log.message,
                details=log.details,
                created_at=log.created_at,
            )
            for log in logs
        ]

        return TrainingLogsResponse(
            task_id=task_id,
            logs=items,
        )
