"""Data providers for the statusline.

Each provider reads local state from ``~/.tribunal/`` and returns structured
data that the formatter/widgets can render.  No network calls, no telemetry.

The ``parse_stdin_data`` function reads the JSON that Claude Code pipes to the
statusline command on every invocation.  This includes context-window usage,
cost, model info, and session metadata.
"""

from __future__ import annotations

import json
import os
import sys
import time
from pathlib import Path
from typing import Any

from launcher.config import get_config, get_memory_dir, get_tribunal_home
from launcher.session import active_session


def parse_stdin_data() -> dict[str, Any]:
    """Read and parse JSON data from stdin (sent by Claude Code).

    Claude Code pipes a JSON blob containing context_window, cost, model,
    session_id, and other metadata to the statusline command on each call.

    Returns an empty dict if stdin is empty, not a TTY, or contains invalid
    JSON.
    """
    try:
        if sys.stdin.isatty():
            return {}
        raw = sys.stdin.read()
        if not raw.strip():
            return {}
        return json.loads(raw)
    except (json.JSONDecodeError, OSError, ValueError):
        return {}


def get_context_usage(stdin_data: dict[str, Any]) -> int | None:
    """Extract context window usage percentage from Claude Code stdin data.

    Returns an integer 0-100, or ``None`` if unavailable.
    """
    ctx = stdin_data.get("context_window")
    if not isinstance(ctx, dict):
        return None
    pct = ctx.get("used_percentage")
    if pct is None:
        return None
    try:
        return round(float(pct))
    except (TypeError, ValueError):
        return None


def persist_context_pct(stdin_data: dict[str, Any]) -> None:
    """Write context percentage to session-scoped cache file.

    The context_monitor hook reads ``context-pct.json`` to decide when
    to trigger continuation warnings.  This function is the *writer*
    that produces that file.  It must run on every statusline invocation.
    """
    pct = get_context_usage(stdin_data)
    if pct is None:
        return

    session_id = stdin_data.get("session_id", "")
    sf_session_id = os.environ.get("SF_SESSION_ID", "").strip() or "default"
    session_dir = get_tribunal_home() / "sessions" / sf_session_id
    session_dir.mkdir(parents=True, exist_ok=True)
    cache_file = session_dir / "context-pct.json"

    payload = {
        "pct": pct,
        "ts": time.time(),
        "session_id": session_id,
    }
    try:
        cache_file.write_text(json.dumps(payload))
    except OSError:
        pass


def get_mode() -> str:
    """Return the current operating mode (e.g. ``'quick'`` or ``'spec'``)."""
    cfg = get_config()
    return str(cfg.get("mode", "quick"))


def get_session_info() -> dict[str, Any] | None:
    """Return the currently active session record, or ``None``.

    The returned dict has at least ``id`` and ``started_at`` keys.
    """
    return active_session()


def get_memory_count() -> int:
    """Return the number of memory files stored in ``~/.tribunal/memory/``."""
    memory_dir: Path = get_memory_dir()
    try:
        return sum(1 for f in memory_dir.iterdir() if f.is_file())
    except OSError:
        return 0
