"""The running list on /issues: decisions for rian, things he must do, issues to address.

Sources of truth: app/services/items.py (the merge, the states, the filter), import/items.json
(items, live-read per request like progress.json), app/models/owner.py (rian's state),
docs/ACCOUNTS.md (Recorded writes: the route shape the oversight lane copies). The write
routes record what rian did; they never edit the items file, which the sessions own through
their script. Every write is `POST /api/items/{id}/<state>` with an optional `text`, needs
`items.act` (the owner's by absence at launch) and records the session's effective account,
never a typed name. `archive` puts an item away for good (open or closed); `reopen` brings
any state back to open. The read takes `show=recent|archived|all`.
"""

from datetime import UTC, datetime

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.db import get_db
from app.models.owner import OwnerItemState
from app.routers.plan import _load as _load_plan
from app.services import discussion as disc
from app.services import identity
from app.services import items as svc

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


class ActIn(BaseModel):
    text: str | None = Field(default=None, max_length=4000)


def _states(db: Session) -> dict[str, dict]:
    rows = db.scalars(select(OwnerItemState)).all()
    return {r.item_id: {"status": r.status, "decision": r.decision, "acted_by": r.acted_by, "acted_at": r.acted_at} for r in rows}


def _plan_tasks() -> dict[str, dict]:
    try:
        plan = _load_plan()
    except HTTPException:
        return {}
    return {t["id"]: t for s in plan.get("streams", []) for t in s.get("tasks", [])}


def _merged(db: Session) -> list[dict]:
    return svc.merge(svc.load_items(), _states(db), plan_tasks=_plan_tasks())


@router.get("")
def read_items(show: str = Query(default="recent"), db: Session = Depends(get_db)) -> dict:
    if show not in svc.SHOWS:
        raise HTTPException(status_code=422, detail={"error_code": "BAD_SHOW", "summary": f"show is one of {', '.join(svc.SHOWS)}"})
    merged = _merged(db)
    path = svc.items_path()
    return {
        "generated_at": datetime.now(UTC).isoformat(timespec="minutes"),
        "file_present": path is not None,
        "show": show,
        "counts": svc.counts(merged),
        "items": svc.shown(merged, show),
    }


def _act(db: Session, item_id: str, status: str, payload: ActIn, request: Request) -> dict:
    items = {i["id"]: i for i in svc.load_items()}
    if item_id not in items:
        raise HTTPException(status_code=404, detail="no such item")
    who = identity.actor(request)
    text = (payload.text or "").strip()
    if status == "done" and items[item_id].get("kind") == "decide":
        # Something was decided: the people in the item's thread hear it as news (a decision is
        # an event kind, never a thread state). The subject is the owner's, so a client never
        # does. Emitted before the row is touched: the lookups precede the first write.
        disc.emit_decision(db, subject_type="item", subject_id=item_id, actor=who,
                           body=text or "Decided.", label=items[item_id].get("title"))
    row = db.get(OwnerItemState, item_id)
    if row is None:
        row = OwnerItemState(item_id=item_id)
        db.add(row)
    row.status = status
    row.decision = text or (None if status == "open" else row.decision)
    row.acted_by = who.display_name
    row.acted_by_id = who.id
    row.acted_at = datetime.now(UTC)
    db.commit()
    merged = {i["id"]: i for i in _merged(db)}
    return merged[item_id]


@router.post("/{item_id}/decide")
def decide(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    if not (payload.text or "").strip():
        raise HTTPException(status_code=422, detail="Write the decision before marking it decided.")
    return _act(db, item_id, "done", payload, request)


@router.post("/{item_id}/done")
def done(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    return _act(db, item_id, "done", payload, request)


@router.post("/{item_id}/dismiss")
def dismiss(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    return _act(db, item_id, "dismissed", payload, request)


@router.post("/{item_id}/archive")
def archive(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    """Put away for good, from any state; the note says why. Reachable behind the filter."""
    return _act(db, item_id, "archived", payload, request)


@router.post("/{item_id}/reopen")
def reopen(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    return _act(db, item_id, "open", payload, request)
