"""Context management commands for Endless Mode.

Implements ``check-context``, ``send-clear``, and ``register-plan`` —
the three session-lifecycle commands used by hooks and rules to drive
automatic context continuation.

How ``send-clear`` works
~~~~~~~~~~~~~~~~~~~~~~~~
Claude Code does not expose IPC to send ``/clear`` to a running session
from the outside.  Instead, the continuation workflow is:

1. Claude (the agent) writes a continuation file.
2. Claude calls ``tribunal send-clear`` via Bash.
3. ``send-clear`` writes a continuation-prompt file and prints ``/clear``
   to **stdout** (which Claude Code interprets as a user message).
4. Claude Code processes ``/clear``, which triggers the SessionEnd hook
   and restarts the session.  The new session picks up the continuation
   prompt via the SessionStart hook.

Because of step 3, ``send-clear`` must be invoked **by Claude inside a
Bash tool call**, not as a standalone process.
"""

from __future__ import annotations

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

from launcher.config import get_tribunal_home, sanitize_session_id

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _sessions_base() -> Path:
    return get_tribunal_home() / "sessions"


def _session_dir() -> Path:
    """Return the session directory for SF_SESSION_ID, creating it if absent."""
    session_id = sanitize_session_id(os.environ.get("SF_SESSION_ID", "").strip())
    d = _sessions_base() / session_id
    d.mkdir(parents=True, exist_ok=True)
    return d


# ---------------------------------------------------------------------------
# check-context
# ---------------------------------------------------------------------------


def check_context(*, as_json: bool = False) -> None:
    """Read the latest context percentage and report it.

    Reads ``context-pct.json`` written by the statusline process.
    Outputs JSON when *as_json* is True, otherwise a human string.
    """
    cache_file = _session_dir() / "context-pct.json"

    pct: float | None = None
    if cache_file.exists():
        try:
            data = json.loads(cache_file.read_text())
            ts = data.get("ts")
            # Accept cache if < 90s old (aligned with context_monitor hook)
            if ts is not None and time.time() - ts < 90:
                pct = float(data["pct"])
        except (json.JSONDecodeError, KeyError, TypeError, ValueError, OSError):
            pass

    if pct is None:
        result = {"status": "UNKNOWN", "percentage": None, "message": "No recent context data"}
    elif pct >= 90:
        result = {"status": "CLEAR_NEEDED", "percentage": pct}
    elif pct >= 80:
        result = {"status": "WARNING", "percentage": pct}
    else:
        result = {"status": "OK", "percentage": pct}

    if as_json:
        print(json.dumps(result))
    else:
        if pct is None:
            print("Context: unknown (no recent data)")
        else:
            print(f"Context: {pct:.0f}% — {result['status']}")


# ---------------------------------------------------------------------------
# register-plan
# ---------------------------------------------------------------------------


def register_plan(plan_path: str, status: str) -> None:
    """Associate a plan file with the current session.

    Writes ``active_plan.json`` so hooks (context_monitor, spec_stop_guard)
    know which plan is active for this session.
    """
    payload = {
        "plan_path": plan_path,
        "status": status.upper(),
        "registered_at": time.time(),
    }
    out_file = _session_dir() / "active_plan.json"
    try:
        out_file.write_text(json.dumps(payload, indent=2) + "\n")
    except OSError:
        pass


# ---------------------------------------------------------------------------
# send-clear
# ---------------------------------------------------------------------------


def send_clear(plan_path: str | None = None, *, general: bool = False) -> None:
    """Prepare session continuation and output ``/clear`` to stdout.

    This command is designed to be called **by Claude via a Bash tool
    call** during the context handoff sequence.  It:

    1. Writes ``continuation-trigger.json`` (signal for diagnostics).
    2. Writes ``continuation-prompt.txt`` (instructions for the next
       session, read by the SessionStart hook).
    3. Prints ``/clear`` to **stdout**.  When called from a Bash tool,
       Claude Code captures this output and presents it to the agent.
       The agent (or the Endless Mode wrapper) then executes ``/clear``
       which restarts the session.

    Parameters
    ----------
    plan_path:
        Path to the active plan file (preferred — preserves plan context).
    general:
        Set to True when there is no active plan.
    """
    session_dir = _session_dir()

    # 1. Write trigger signal (for diagnostics / polling by external tools)
    trigger_payload: dict[str, object] = {
        "action": "send-clear",
        "timestamp": time.time(),
        "sf_session_id": os.environ.get("SF_SESSION_ID", ""),
    }
    if plan_path:
        trigger_payload["plan_path"] = plan_path
    elif general:
        trigger_payload["general"] = True

    signal_file = session_dir / "continuation-trigger.json"
    try:
        signal_file.write_text(json.dumps(trigger_payload, indent=2) + "\n")
    except OSError:
        pass

    # 2. Write continuation prompt for the next session
    if plan_path:
        continuation_prompt = f"/spec --continue {plan_path}"
    else:
        continuation_prompt = (
            "Continue from previous session. Read the continuation file and Tribunal Memory for context."
        )
    prompt_file = session_dir / "continuation-prompt.txt"
    try:
        prompt_file.write_text(continuation_prompt + "\n")
    except OSError as exc:
        print(f"Warning: could not write continuation prompt: {exc}", file=sys.stderr)

    # 3. Print status to stderr (visible to user) and /clear to stdout
    #    (captured by Claude Code's Bash tool as the command output).
    print("Session continuation prepared.", file=sys.stderr)
    if plan_path:
        print(f"Plan: {plan_path}", file=sys.stderr)
    print("Sending /clear to restart session...", file=sys.stderr)

    # The agent's rules instruct it to execute this command, capture the
    # output, and then the Endless Mode wrapper handles the actual /clear.
    # We print it to stdout so it appears in the Bash tool result.
    print("/clear")
