"""Kanban tasks."""
from datetime import datetime, timezone
from bson import ObjectId
from bson.errors import InvalidId
from fastapi import APIRouter, Depends, HTTPException

from deps import get_db, get_current_user, require_roles
from models import TaskIn, TaskUpdate

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


def _oid(s: str) -> ObjectId:
    try:
        return ObjectId(s)
    except InvalidId:
        raise HTTPException(status_code=400, detail="ID inválido")


def _ser(t: dict) -> dict:
    return {
        "id": str(t["_id"]),
        "project_id": t["project_id"],
        "title": t["title"],
        "description": t.get("description", ""),
        "status": t.get("status", "backlog"),
        "priority": t.get("priority", "medium"),
        "assignee_id": t.get("assignee_id"),
        "due_date": t.get("due_date"),
        "created_at": t.get("created_at"),
        "updated_at": t.get("updated_at"),
    }


@router.get("")
async def list_tasks(project_id: str, user: dict = Depends(get_current_user)):
    db = get_db()
    # access guard
    p = await db.projects.find_one({"_id": _oid(project_id)})
    if not p:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
    if user["role"] == "client":
        raise HTTPException(status_code=403, detail="Sin acceso")
    if user["role"] == "collaborator" and user["id"] not in (p.get("collaborator_ids") or []):
        raise HTTPException(status_code=403, detail="Sin acceso")
    cursor = db.tasks.find({"project_id": project_id}).sort("created_at", 1)
    return [_ser(t) async for t in cursor]


@router.post("")
async def create_task(payload: TaskIn, _: dict = Depends(require_roles("admin", "pm", "collaborator"))):
    db = get_db()
    now = datetime.now(timezone.utc).isoformat()
    doc = {**payload.model_dump(), "created_at": now, "updated_at": now}
    res = await db.tasks.insert_one(doc)
    doc["_id"] = res.inserted_id
    return _ser(doc)


@router.patch("/{task_id}")
async def update_task(task_id: str, payload: TaskUpdate, _: dict = Depends(require_roles("admin", "pm", "collaborator"))):
    db = get_db()
    oid = _oid(task_id)
    update = {k: v for k, v in payload.model_dump(exclude_unset=True).items()}
    if not update:
        raise HTTPException(status_code=400, detail="Nada para actualizar")
    update["updated_at"] = datetime.now(timezone.utc).isoformat()
    res = await db.tasks.find_one_and_update({"_id": oid}, {"$set": update}, return_document=True)
    if not res:
        raise HTTPException(status_code=404, detail="Tarea no encontrada")
    return _ser(res)


@router.delete("/{task_id}")
async def delete_task(task_id: str, _: dict = Depends(require_roles("admin", "pm"))):
    db = get_db()
    oid = _oid(task_id)
    res = await db.tasks.delete_one({"_id": oid})
    if res.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Tarea no encontrada")
    return {"ok": True}
