"""API проектов M1."""

from typing import Any, cast

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

from app.dependencies import DbDep, UserIdDep
from app.models import CoinEvent, Project
from app.realtime import publish
from app.schemas import ProjectCreate, ProjectOut, ProjectUpdate
from app.services.xp import coins_for_create, grant_create_xp

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

# «Закрыт» (archived) больше нет — вместо него архив (ТЗ 3.8.1)
VALID_RELEVANCE = {"active", "paused"}


def _get_project_or_404(db: Any, project_id: int, user_id: str) -> Project:
    project = cast(
        Project | None,
        db.scalar(select(Project).where(Project.id == project_id, Project.user_id == user_id)),
    )
    if project is None:
        raise HTTPException(status_code=404, detail="Project not found")
    return project


@router.post("", response_model=ProjectOut)
async def create_project(
    schema: ProjectCreate, db: DbDep, user_id: UserIdDep, response: Response
) -> Project:
    exists = db.scalars(
        select(Project).where(Project.name == schema.name, Project.user_id == user_id)
    ).first()
    if exists is not None:
        raise HTTPException(status_code=409, detail="Project name already exists")
    project = Project(user_id=user_id, name=schema.name, priority=schema.priority, note=schema.note)
    db.add(project)
    db.flush()
    # Микронаграда за создание (ТЗ 3.13): чуть больше XP, чем за задачу
    grant_create_xp(db, "create_project", user_id)
    db.add(
        CoinEvent(
            user_id=user_id, source="create_project", amount=coins_for_create("create_project")
        )
    )
    response.headers["X-Created-XP"] = "5"
    response.headers["X-Created-Coins"] = "2"
    db.commit()
    publish(user_id, "project.changed", {"id": project.id})
    publish(user_id, "xp.changed", {"celebrate": False})
    return project


@router.get("", response_model=list[ProjectOut])
async def list_projects(
    db: DbDep, user_id: UserIdDep, archived: bool = Query(False)
) -> list[Project]:
    """Активные проекты; archived=true — список архива (история)."""
    return list(
        db.scalars(
            select(Project)
            .where(Project.is_archived == archived, Project.user_id == user_id)
            .order_by(Project.id)
        ).all()
    )


@router.get("/{project_id}", response_model=ProjectOut)
async def get_project(project_id: int, db: DbDep, user_id: UserIdDep) -> Project:
    return _get_project_or_404(db, project_id, user_id)


@router.patch("/{project_id}", response_model=ProjectOut)
async def update_project(
    project_id: int, schema: ProjectUpdate, db: DbDep, user_id: UserIdDep
) -> Project:
    project = _get_project_or_404(db, project_id, user_id)
    data = schema.model_dump(exclude_unset=True)
    if "relevance_status" in data and data["relevance_status"] not in VALID_RELEVANCE:
        raise HTTPException(
            status_code=422, detail=f"Unknown relevance_status: {data['relevance_status']}"
        )
    if "name" in data and data["name"] != project.name:
        exists = db.scalars(
            select(Project).where(Project.name == data["name"], Project.user_id == user_id)
        ).first()
        if exists is not None:
            raise HTTPException(status_code=409, detail="Project name already exists")
    for field, value in data.items():
        setattr(project, field, value)
    db.commit()
    publish(user_id, "project.changed", {"id": project.id})
    return project


@router.post("/{project_id}/archive", response_model=ProjectOut)
async def archive_project(project_id: int, db: DbDep, user_id: UserIdDep) -> Project:
    """Отправить проект в архив — вместе со всеми его задачами (ТЗ 3.8.1)."""
    project = _get_project_or_404(db, project_id, user_id)
    project.is_archived = True
    db.commit()
    publish(user_id, "project.changed", {"id": project.id})
    return project


@router.post("/{project_id}/restore", response_model=ProjectOut)
async def restore_project(project_id: int, db: DbDep, user_id: UserIdDep) -> Project:
    """Вернуть проект из архива — со всеми задачами и историей."""
    project = _get_project_or_404(db, project_id, user_id)
    project.is_archived = False
    db.commit()
    publish(user_id, "project.changed", {"id": project.id})
    return project


@router.delete("/{project_id}")
async def delete_project(project_id: int, db: DbDep, user_id: UserIdDep) -> dict[str, bool]:
    project = _get_project_or_404(db, project_id, user_id)
    db.delete(project)
    db.commit()
    publish(user_id, "project.deleted", {"id": project_id})
    return {"ok": True}
