"""Comments on the guide -- the app's own routes over the file-backed store.

Every route here is protected twice: the default-deny middleware (a session is
required to reach /api/* at all) and the `member_user` dependency below (the
session's EFFECTIVE user must hold a level in THIS app, or be the owner). A BW
account that exists but was never added to atlas gets a 403 with a friendly code,
never the content -- the guide describes the server's internals and is for the
team, not for every account the identity host knows about.

Subjects are `<area>/<slug>` -- today only the `guide` area (one file per
chapter). Section anchors are slugs the frontend chooses; the store only checks
their shape. Author is ALWAYS the session user: nobody can post as someone else,
which is what makes the reserved `claude` author meaningful (it can only arrive
by a Claude session editing the file).
"""

from fastapi import APIRouter, Body, Depends, HTTPException, Request
from pydantic import BaseModel, Field

from app import accounts
from app import bw_accounts as bwa
from app.config import get_settings
from app.identity import optional_user
from app.services.comments_store import CommentsError, CommentsStore

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

AREA = "guide"

_STATUS = {"BAD_INPUT": 400, "EMPTY_BODY": 400, "BODY_TOO_LONG": 400,
           "NO_SUCH_THREAD": 404, "NO_SUCH_ENTRY": 404, "FORBIDDEN": 403,
           "TOO_MANY_THREADS": 409, "THREAD_FULL": 409}


def _raise(exc: CommentsError):
    raise HTTPException(
        status_code=_STATUS.get(exc.code, 400),
        detail={"error_code": exc.code, "summary": exc.summary, "details": exc.details},
    )


def store() -> CommentsStore:
    return CommentsStore(get_settings().data_dir / "comments")


def is_member(username: str | None) -> bool:
    return bool(username) and bwa.member(username) is not None


def can_moderate(username: str | None) -> bool:
    """Resolve/reopen anyone's thread, delete anyone's comment: the owner, or a
    level that carries the accounts-management permission (the admin seed)."""
    if not username:
        return False
    return accounts.is_owner(username) or accounts.app_can(username, bwa.PERM_ACCOUNTS_VIEW)


def member_user(user: str | None = Depends(optional_user)) -> str:
    if not is_member(user):
        raise HTTPException(
            status_code=403,
            detail={"error_code": "NOT_A_MEMBER",
                    "summary": "You have not been given access to Atlas yet.",
                    "details": "Ask the owner to add your account to this app."})
    return user  # type: ignore[return-value]


class NewThread(BaseModel):
    section: str = Field(min_length=1, max_length=64)
    body: str = Field(min_length=1, max_length=8000)


class NewReply(BaseModel):
    body: str = Field(min_length=1, max_length=8000)


class NewStatus(BaseModel):
    status: str = Field(pattern="^(open|resolved)$")


@router.get("")
def counts(_user: str = Depends(member_user)) -> dict:
    """Per-chapter counts for the navigation badges."""
    try:
        return {"counts": store().counts(AREA)}
    except CommentsError as exc:
        _raise(exc)


@router.get("/{chapter}")
def list_threads(chapter: str, user: str = Depends(member_user)) -> dict:
    try:
        threads = store().threads(AREA, chapter)
    except CommentsError as exc:
        _raise(exc)
    return {"chapter": chapter, "can_moderate": can_moderate(user),
            "threads": [t.as_dict() for t in threads]}


@router.post("/{chapter}", status_code=201)
def new_thread(chapter: str, payload: NewThread = Body(...),
               user: str = Depends(member_user)) -> dict:
    try:
        t = store().add_thread(AREA, chapter, payload.section, user, payload.body)
    except CommentsError as exc:
        _raise(exc)
    return {"thread": t.as_dict()}


@router.post("/{chapter}/{thread_id}/reply")
def reply(chapter: str, thread_id: str, payload: NewReply = Body(...),
          user: str = Depends(member_user)) -> dict:
    try:
        t = store().reply(AREA, chapter, thread_id, user, payload.body)
    except CommentsError as exc:
        _raise(exc)
    return {"thread": t.as_dict()}


@router.post("/{chapter}/{thread_id}/status")
def set_status(chapter: str, thread_id: str, payload: NewStatus = Body(...),
               user: str = Depends(member_user)) -> dict:
    s = store()
    try:
        current = next((t for t in s.threads(AREA, chapter) if t.id == thread_id), None)
        if current is None:
            raise CommentsError("NO_SUCH_THREAD", "That thread does not exist.")
        starter = current.entries[0].author if current.entries else ""
        if not (can_moderate(user) or starter == user):
            raise CommentsError("FORBIDDEN", "Only the person who started this "
                                "thread (or an admin) can resolve it.")
        t = s.set_status(AREA, chapter, thread_id, payload.status)
    except CommentsError as exc:
        _raise(exc)
    return {"thread": t.as_dict()}


@router.delete("/{chapter}/{thread_id}/{index}")
def delete_entry(chapter: str, thread_id: str, index: int, request: Request,
                 user: str = Depends(member_user)) -> dict:
    s = store()
    try:
        current = next((t for t in s.threads(AREA, chapter) if t.id == thread_id), None)
        if current is None:
            raise CommentsError("NO_SUCH_THREAD", "That thread does not exist.")
        if index < 0 or index >= len(current.entries):
            raise CommentsError("NO_SUCH_ENTRY", "That comment does not exist.")
        if not (can_moderate(user) or current.entries[index].author == user):
            raise CommentsError("FORBIDDEN", "You can only delete your own comments.")
        t = s.delete_entry(AREA, chapter, thread_id, index)
    except CommentsError as exc:
        _raise(exc)
    return {"thread": t.as_dict() if t else None}
