"""API задач M1: быстрый захват, стек, ручная детализация, CRUD."""

from typing import Any, cast

from fastapi import APIRouter, HTTPException, Query
from sqlalchemy import select

from app.dependencies import DbDep, UserDep
from app.models import Project, Tag, Task, utcnow
from app.schemas import TaskCreate, TaskOut, TaskUpdate

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

VALID_STATUSES = {"to_do", "in_progress", "done", "cancelled", "deferred"}


def _get_task_or_404(db: Any, task_id: int) -> Task:
    task = cast(Task | None, db.get(Task, task_id))
    if task is None:
        raise HTTPException(status_code=404, detail="Task not found")
    return task


@router.post("")
async def create_task(schema: TaskCreate, db: DbDep, user: UserDep) -> dict[str, int]:
    """Быстрый захват: достаточно title — задача попадает в стек (raw, to_do)."""
    task = Task(title=schema.title, description=schema.description)
    db.add(task)
    db.flush()
    return {"id": task.id}


@router.get("", response_model=list[TaskOut])
async def list_tasks(
    db: DbDep,
    user: UserDep,
    detail_state: str | None = Query(None),
    status: str | None = Query(None),
    project_id: int | None = Query(None),
) -> list[Task]:
    stmt = select(Task).order_by(Task.created_at.desc())
    if detail_state:
        stmt = stmt.where(Task.detail_state == detail_state)
    if status:
        stmt = stmt.where(Task.status == status)
    if project_id:
        stmt = stmt.where(Task.project_id == project_id)
    return list(db.scalars(stmt).all())


@router.get("/{task_id}", response_model=TaskOut)
async def get_task(task_id: int, db: DbDep, user: UserDep) -> Task:
    return _get_task_or_404(db, task_id)


@router.patch("/{task_id}", response_model=TaskOut)
async def update_task(task_id: int, schema: TaskUpdate, db: DbDep, user: UserDep) -> Task:
    task = _get_task_or_404(db, task_id)
    data = schema.model_dump(exclude_unset=True)

    if "title" in data and not str(data["title"]).strip():
        raise HTTPException(status_code=422, detail="title cannot be empty")
    if "status" in data and data["status"] not in VALID_STATUSES:
        raise HTTPException(status_code=422, detail=f"Unknown status: {data['status']}")
    if "project_id" in data and data["project_id"] is not None:
        if db.get(Project, data["project_id"]) is None:
            raise HTTPException(status_code=400, detail="Unknown project")
    if "tag_ids" in data:
        tag_ids = data.pop("tag_ids") or []
        tags = db.scalars(select(Tag).where(Tag.id.in_(tag_ids))).all()
        if len(tags) != len(set(tag_ids)):
            raise HTTPException(status_code=400, detail="Unknown tag id in tag_ids")
        task.tags = list(tags)

    for field, value in data.items():
        setattr(task, field, value)
    if data.get("status") == "done" and task.done_at is None:
        task.done_at = utcnow()

    db.flush()
    db.refresh(task)  # перечитать связи (project/tags) после обновления
    return task


@router.post("/{task_id}/approve", response_model=TaskOut)
async def approve_task(task_id: int, db: DbDep, user: UserDep) -> Task:
    """Утверждение детализации: raw → approved."""
    task = _get_task_or_404(db, task_id)
    task.detail_state = "approved"
    task.approved_at = utcnow()
    return task


@router.delete("/{task_id}")
async def delete_task(task_id: int, db: DbDep, user: UserDep) -> dict[str, bool]:
    db.delete(_get_task_or_404(db, task_id))
    return {"ok": True}
