"""Public read-only view of a shared chat.

A share link is a capability token: the holder reads the session's display
history and nothing else. There is no auth on these endpoints by design — the
recipient is typically someone without a Navi account — so they must stay
strictly read-only and must never expose more than the owner's own chat feed:

  - only display history (``get_history_page``) — never the LLM context,
    planning logs, todos, terminals or the session's file listing;
  - no session id or owner id in the payload (content URLs inside tool results
    are the pre-existing artifact links and carry the session id themselves);
  - a deleted session or an unknown token answers 404 alike, so a link cannot
    be used to probe for sessions.
"""

from typing import Annotated

import structlog
from fastapi import APIRouter, Depends, HTTPException, Query

from navi.api.deps import get_profile_registry, get_session_store
from navi.core import ProfileRegistry, SessionStore
from navi.exceptions import ProfileNotFound
from navi.llm.base import Message

log = structlog.get_logger()

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


async def _load(token: str, store: SessionStore):
    share = await store.get_share(token)
    if share is None:
        raise HTTPException(status_code=404, detail="Share not found")
    session = await store.get_meta(share["session_id"])
    if session is None:
        raise HTTPException(status_code=404, detail="Share not found")
    return share, session


def _profile_name(profiles: ProfileRegistry, profile_id: str | None) -> str | None:
    if not profile_id:
        return None
    try:
        return profiles.get(profile_id).name
    except ProfileNotFound:
        return None


def _items(messages: list[Message]) -> list[dict]:
    return [m.model_dump(mode="json", exclude_none=True) for m in messages]


@router.get("/{token}")
async def get_shared_chat(
    token: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
    profiles: Annotated[ProfileRegistry, Depends(get_profile_registry)],
    limit: int = Query(200, ge=1, le=200),
) -> dict:
    """The shared chat's head plus its newest page of messages."""
    share, session = await _load(token, store)
    msgs, has_more = await store.get_history_page(
        share["session_id"], before_seq=None, limit=limit
    )
    return {
        "name": session.name,
        "profile_id": session.profile_id,
        "profile_name": _profile_name(profiles, session.profile_id),
        "created_at": session.created_at.isoformat(),
        "last_active": session.last_active.isoformat(),
        "messages": _items(msgs),
        "has_more": has_more,
        "next_before_seq": msgs[0].sequence_number if msgs else None,
    }


@router.get("/{token}/messages")
async def get_shared_history(
    token: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
    before_seq: int | None = None,
    limit: int = Query(150, ge=1, le=200),
) -> dict:
    """Older page of the shared history, for scroll-up loading."""
    share, _ = await _load(token, store)
    msgs, has_more = await store.get_history_page(
        share["session_id"], before_seq=before_seq, limit=limit
    )
    return {
        "messages": _items(msgs),
        "has_more": has_more,
        "next_before_seq": msgs[0].sequence_number if msgs else None,
    }
