"""Unified task routes."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import ValidationError
from sqlalchemy.orm import Session

from app.core.config import settings
from app.core.db import get_db
from app.schemas.tasks import (
    CoverageTaskSyncResponse,
    TaskCompleteResponse,
    TaskCreateRequest,
    TodoistTaskRead,
)
from app.services import coverage_engine
from app.services.integrations import service as integrations_service
from app.services.integrations.errors import IntegrationError, ProviderConnectionError, ProviderDisabledError, ProviderNotConfiguredError

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


def _raise_from_task_error(exc: Exception) -> None:
    """Map provider exceptions to HTTP responses."""
    if isinstance(exc, LookupError):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    if isinstance(exc, ProviderNotConfiguredError):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        ) from exc
    if isinstance(exc, ProviderDisabledError):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
    if isinstance(exc, ProviderConnectionError):
        raise HTTPException(status_code=status.HTTP_502_BAD_GATEWAY, detail=str(exc)) from exc
    if isinstance(exc, IntegrationError):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
    raise exc


@router.post("/create", response_model=TodoistTaskRead, status_code=status.HTTP_201_CREATED)
def create_task(payload: TaskCreateRequest) -> TodoistTaskRead:
    """Create one task in selected/default provider."""
    try:
        task = integrations_service.create_task(
            content=payload.content,
            description=payload.description,
            due_string=payload.due_string,
            provider_id=payload.provider,
        )
    except Exception as exc:  # pragma: no cover - mapped to explicit HTTP errors
        _raise_from_task_error(exc)
    return TodoistTaskRead.model_validate(task)


@router.get("", response_model=list[TodoistTaskRead])
def list_tasks(
    provider: str | None = Query(default=None, min_length=1),
    across_all: bool = Query(default=True),
    include_completed: bool = Query(default=False),
) -> list[TodoistTaskRead]:
    """List tasks from enabled providers."""
    try:
        tasks = integrations_service.list_tasks(
            provider_id=provider,
            across_all=across_all,
            include_completed=include_completed,
        )
    except Exception as exc:  # pragma: no cover - mapped to explicit HTTP errors
        _raise_from_task_error(exc)
    try:
        return [TodoistTaskRead.model_validate(task) for task in tasks]
    except ValidationError as exc:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail="Unexpected tasks response format",
        ) from exc


@router.post("/complete", response_model=TaskCompleteResponse)
def complete_task(
    task_id: str = Query(..., min_length=1),
    provider: str | None = Query(default=None, min_length=1),
) -> TaskCompleteResponse:
    """Complete one task by provider/id."""
    try:
        integrations_service.complete_task(task_id=task_id, provider_id=provider)
    except Exception as exc:  # pragma: no cover - mapped to explicit HTTP errors
        _raise_from_task_error(exc)
    return TaskCompleteResponse(status="completed", task_id=task_id, provider=provider)


@router.post("/from-coverage", response_model=CoverageTaskSyncResponse)
def create_tasks_from_coverage(
    engagement_id: int | None = Query(default=None, ge=1),
    provider: str | None = Query(default=None, min_length=1),
    db: Session = Depends(get_db),
) -> CoverageTaskSyncResponse:
    """Create tasks for uncovered engagement phases in target/default provider."""
    if engagement_id is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="engagement_id is required",
        )

    try:
        coverage = coverage_engine.get_coverage(db=db, engagement_id=engagement_id)
    except LookupError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc

    task_titles = [f"[{settings.app_name}] Explore phase: {phase}" for phase in coverage.gaps]
    description = (
        f"Coverage gap detected for engagement {engagement_id}. "
        "Phase requires additional validation."
    )
    try:
        created_tasks, skipped_tasks = integrations_service.create_coverage_tasks(
            task_titles=task_titles,
            description_template=description,
            provider_id=provider,
        )
    except Exception as exc:  # pragma: no cover - mapped to explicit HTTP errors
        _raise_from_task_error(exc)

    return CoverageTaskSyncResponse(
        engagement_id=engagement_id,
        provider=provider,
        created_tasks=created_tasks,
        skipped_tasks=skipped_tasks,
    )
