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

Sources of truth: app/services/items.py (the merge), import/items.json (items, live-read per
request like progress.json), app/models/owner.py (rian's state). The write routes record what
rian did; they never edit the items file, which the sessions own through their script.
The write routes need `items.act` (the owner's by absence at launch) and record the
session's effective account, never a typed name.
"""

from datetime import UTC, datetime

from fastapi import APIRouter, Depends, HTTPException, 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 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(db: Session = Depends(get_db)) -> dict:
    merged = _merged(db)
    path = svc.items_path()
    return {
        "generated_at": datetime.now(UTC).isoformat(timespec="minutes"),
        "file_present": path is not None,
        "counts": svc.counts(merged),
        "items": [i for i in merged if i["visible"]],
    }


def _act(db: Session, item_id: str, status: str, payload: ActIn, request: Request) -> dict:
    ids = {i["id"] for i in svc.load_items()}
    if item_id not in ids:
        raise HTTPException(status_code=404, detail="no such item")
    who = identity.actor(request)
    row = db.get(OwnerItemState, item_id)
    if row is None:
        row = OwnerItemState(item_id=item_id)
        db.add(row)
    row.status = status
    row.decision = (payload.text or "").strip() 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}/reopen")
def reopen(item_id: str, payload: ActIn, request: Request, db: Session = Depends(get_db)) -> dict:
    return _act(db, item_id, "open", payload, request)
