"""
events.py
---------
Routes exposing the event log and narration utilities for HIEROMEM.
"""

from __future__ import annotations

from enum import Enum
from typing import Callable, cast

from fastapi import APIRouter, Depends, HTTPException

from hieromem_core.events import EventLog, MemoryEvent
from hieromem_core.narrator import Narrator
from hieromem_api.deps import get_memory_engine
from hieromem_api.models.responses import EventRecord, NarrationResponse
from hieromem_api.auth import require_api_key, require_permission
from hieromem_api.rbac import Permission
from hieromem_api.tenants import Tenant, resolve_tenant

# --------------------------------------------------------------------------- #
# Router setup
# --------------------------------------------------------------------------- #

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

memory = get_memory_engine()
narrator = getattr(memory, "narrator", Narrator())


class NarrationMode(str, Enum):
    """Valid narration modes exposed by /events/narrate."""

    RECENT = "recent"
    STORY = "story"
    SUMMARY = "summary"


def _event_log() -> EventLog:
    event_log = getattr(memory, "event_log", None)
    if not isinstance(event_log, EventLog):
        raise HTTPException(status_code=503, detail="Event log unavailable.")
    return event_log


def _serialize_event(event: MemoryEvent, *, idx: int |
                     None = None) -> EventRecord:
    episode_id = getattr(event, "episode_id", None)
    if episode_id is None and event.details:
        episode_id = event.details.get("episode_id")
    return EventRecord(
        idx=idx,
        event_type=event.event_type.value,
        message=event.message,
        timestamp=event.timestamp.isoformat(),
        level=getattr(event, "level", "info"),
        duration=getattr(event, "duration", None),
        source=getattr(event, "source", None),
        session_id=getattr(event, "session_id", None),
        episode_id=episode_id,
        details=event.details or None,
    )


def _ensure_positive_limit(limit: int) -> int:
    return max(limit, 1)


def _active_narrator() -> Narrator:
    return cast(Narrator, getattr(memory, "narrator", narrator))


def _narrate_story(limit: int) -> str:
    story = _active_narrator().story(limit)
    return story or "No narrative events recorded yet."


def _narrate_summary(limit: int) -> str:
    summary: str | None = _active_narrator().summarize_recent()
    if summary is not None:
        return summary
    return _narrate_story(limit)


_NARRATION_HANDLERS: dict[NarrationMode, Callable[[int], str]] = {
    NarrationMode.RECENT: _narrate_story,
    NarrationMode.STORY: _narrate_story,
    NarrationMode.SUMMARY: _narrate_summary,
}

# --------------------------------------------------------------------------- #
# Endpoints
# --------------------------------------------------------------------------- #


@router.get("/", response_model=list[EventRecord])
def get_recent_events(
    limit: int = 20,
    tenant: Tenant = Depends(require_api_key),
    _perm_check: None = Depends(require_permission(Permission.READ_MEMORY)),
) -> list[EventRecord]:
    """Return the most recent N memory events."""

    resolve_tenant(tenant)
    event_log = _event_log()
    limit = _ensure_positive_limit(limit)
    events = event_log.recent(limit)
    records = [_serialize_event(ev, idx=idx) for idx, ev in enumerate(events)]
    return records


@router.get("/timeline", response_model=list[EventRecord])
def timeline(
    tenant: Tenant = Depends(require_api_key),
    _perm_check: None = Depends(require_permission(Permission.READ_MEMORY)),
) -> list[EventRecord]:
    """Return a full chronological history of memory events."""

    resolve_tenant(tenant)
    event_log = _event_log()
    events = event_log.all()
    records = [_serialize_event(ev, idx=idx) for idx, ev in enumerate(events)]
    return records


@router.get("/narrate", response_model=NarrationResponse)
def narrate(
    limit: int = 20,
    mode: str | None = "recent",
    tenant: Tenant = Depends(require_api_key),
    _perm_check: None = Depends(require_permission(Permission.READ_MEMORY)),
) -> NarrationResponse:
    """Generate a human-readable narrative of memory dynamics."""

    resolve_tenant(tenant)
    _event_log()  # ensure log exists even if empty
    limit = _ensure_positive_limit(limit)

    try:
        selected_mode = NarrationMode(mode or NarrationMode.RECENT)
    except ValueError as exc:  # pragma: no cover - FastAPI will surface HTTPException
        raise HTTPException(status_code=400,
                            detail=f"Unsupported mode: {mode}") from exc

    handler = _NARRATION_HANDLERS[selected_mode]
    text = handler(limit)
    return NarrationResponse(mode=selected_mode.value, narration=text)
