# tools/timer_tools.py — Agent-accessible short timers (Phase 2b §1).
#
# Persisted in ``~/.mugi/timers.jsonl`` and drained by mugi_runner's dedicated
# timer drain thread; see ``utils.timers`` and ``mugi_runner._timer_drain_loop``.
# Timers bypass ``activeHours`` because user-requested reminders must fire on
# schedule; they still respect ``[timers].enabled``.
from __future__ import annotations

from langchain_core.tools import tool
from pydantic import BaseModel, Field
from tools._logging import _debug_log, _emit_input_status


def _block_in_subagent() -> str | None:
    """Return a refusal string if this tool is being invoked from a child subagent."""
    try:
        from tool_policy import get_current_policy_context
        ctx = get_current_policy_context()
        if ctx is not None and bool(getattr(ctx, "subagent_mode", False)):
            return "Timers can only be scheduled by the main agent, not by delegated subagents."
    except Exception:
        pass
    return None


def _timers_enabled() -> bool:
    try:
        from utils.timers import is_enabled
        return is_enabled()
    except Exception:
        return False


def _resolve_thread_id(thread_id: str) -> str:
    thread_id = (thread_id or "").strip()
    if thread_id and thread_id.lower() != "current":
        return thread_id
    try:
        from persistence import get_current_agent_thread_id
        tid = (get_current_agent_thread_id() or "").strip()
        if tid:
            return tid
    except Exception:
        pass
    return ""


class ScheduleTimerInput(BaseModel):
    delay: str = Field(
        description=(
            "When the timer fires. Accepts '30m', '2h', '1d', integer seconds, "
            "or an ISO-8601 timestamp. Minimum 60 s, maximum 30 days."
        )
    )
    message: str = Field(
        description="Reminder text shown to the user when the timer fires (<= 4 KB)."
    )
    thread_id: str = Field(
        default="current",
        description="Thread to deliver the reminder to. 'current' = current conversation.",
    )


@tool(args_schema=ScheduleTimerInput)
def schedule_timer(delay: str, message: str, thread_id: str = "current") -> str:
    """Schedule a one-shot reminder. Fires into the origin thread (or as a
    macOS notification if no thread is available) at the requested moment.
    Use for short, user-requested nudges — not for recurring jobs. Timers
    bypass quiet hours; use schedule_task for recurring / cron-style work.
    """
    _debug_log(f"[TOOL] schedule_timer called: delay={delay}", "TOOL")
    refusal = _block_in_subagent()
    if refusal:
        return refusal
    if not _timers_enabled():
        return (
            "Timers are disabled. Enable them in Preferences → Advanced → Short timers "
            "before scheduling reminders."
        )
    _emit_input_status("Scheduling timer…")
    try:
        from utils import timers as _timers
        tid = _resolve_thread_id(thread_id)
        row = _timers.schedule(
            delay,
            message,
            thread_id=tid or None,
            origin="agent",
            kind="reminder",
        )
    except ValueError as e:
        _emit_input_status("")
        return f"Could not schedule timer: {e}"
    except Exception as e:
        _emit_input_status("")
        return f"Unexpected error scheduling timer: {e}"
    _emit_input_status("")
    fire_at = row.get("fire_at")
    where = f"in thread {tid}" if tid else "as a notification"
    return f"Timer {row['id']} set for {fire_at} ({where})."


class CancelTimerInput(BaseModel):
    timer_id: str = Field(description="ID returned by schedule_timer (e.g. 'tmr_…').")


@tool(args_schema=CancelTimerInput)
def cancel_timer(timer_id: str) -> str:
    """Cancel a pending timer. Already-fired or unknown timers are reported."""
    _debug_log(f"[TOOL] cancel_timer called: timer_id={timer_id}", "TOOL")
    refusal = _block_in_subagent()
    if refusal:
        return refusal
    if not _timers_enabled():
        return "Timers are disabled; nothing to cancel."
    try:
        from utils import timers as _timers
        ok = _timers.cancel(timer_id)
    except Exception as e:
        return f"Could not cancel timer {timer_id}: {e}"
    return f"Cancelled timer {timer_id}." if ok else f"No pending timer with id {timer_id}."


class ListTimersInput(BaseModel):
    thread_id: str = Field(
        default="current",
        description="Restrict to a thread, or 'all' to see every pending timer.",
    )


@tool(args_schema=ListTimersInput)
def list_timers(thread_id: str = "current") -> str:
    """List pending timers for a thread (default: current conversation)."""
    _debug_log(f"[TOOL] list_timers called", "TOOL")
    refusal = _block_in_subagent()
    if refusal:
        return refusal
    if not _timers_enabled():
        return "Timers are disabled."
    try:
        from utils import timers as _timers
        if (thread_id or "").strip().lower() == "all":
            rows = _timers.list_pending()
        else:
            tid = _resolve_thread_id(thread_id)
            rows = _timers.list_pending(thread_id=tid or None)
    except Exception as e:
        return f"Could not list timers: {e}"
    if not rows:
        return "No pending timers."
    lines = []
    for r in rows[:20]:
        msg = str(r.get("message") or "")
        if len(msg) > 80:
            msg = msg[:77] + "…"
        where = r.get("thread_id") or "notification"
        lines.append(f"- {r.get('id')} @ {r.get('fire_at')} → {where}: {msg}")
    if len(rows) > 20:
        lines.append(f"… and {len(rows) - 20} more.")
    return "\n".join(lines)
