"""Chat router — v1-parity assistant chat over the pinned SSE contract.

Async routes (AI/SSE per standards). The message route prepares the turn
inside a short sync DB session (commit before streaming), then streams the
function-calling loop; stream_turn opens its own short sessions for tool
dispatch + persistence between awaits.
"""
from __future__ import annotations

from fastapi import APIRouter, Depends, File, Form, Request, UploadFile
from sqlalchemy.orm import Session
from sse_starlette.sse import EventSourceResponse

from ..db import get_db
from ..deps import current_garden_id
from ..services.ai import chat as svc

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


@router.post("/sessions", status_code=201)
def create_session(
    db: Session = Depends(get_db), garden_id: int = Depends(current_garden_id)
) -> dict:
    out = svc.create_session(db, garden_id)
    db.commit()
    return out


@router.get("/sessions")
def list_sessions(
    db: Session = Depends(get_db), garden_id: int = Depends(current_garden_id)
) -> list[dict]:
    return svc.list_sessions(db, garden_id)


@router.get("/sessions/{session_id}")
def get_session(
    session_id: int,
    db: Session = Depends(get_db),
    garden_id: int = Depends(current_garden_id),
) -> dict:
    return svc.get_session_replay(db, garden_id, session_id)


@router.post("/sessions/{session_id}/end")
async def end_session(
    session_id: int,
    garden_id: int = Depends(current_garden_id),
) -> dict:
    # end_session manages its own short DB sessions (it awaits the titling
    # provider between them), so no request-scoped session here.
    return await svc.end_session(garden_id=garden_id, session_id=session_id)


@router.post("/sessions/{session_id}/messages")
async def post_message(
    session_id: int,
    request: Request,
    text: str = Form(""),
    photos: list[UploadFile] = File(default=[]),
    db: Session = Depends(get_db),
    garden_id: int = Depends(current_garden_id),
) -> EventSourceResponse:
    ctx = svc.prepare_turn(
        db, garden_id, session_id, text=text, photos=photos
    )
    # Commit the user message BEFORE streaming so it survives provider
    # failures, and release this request-scoped session — stream_turn opens
    # its own short sessions between awaits (standards: no session held
    # across awaits).
    db.commit()

    async def gen():
        async for ev in svc.stream_turn(ctx):
            if await request.is_disconnected():
                break
            yield {"event": ev.type, "data": ev.model_dump_json()}

    return EventSourceResponse(gen())
