# tools/calendar_tools.py — Agent tools for reading the user's calendar.
# Calendar access is handled by the Swift app's localhost bridge (EventKit identity + TCC prompts).
from __future__ import annotations

import json

from langchain_core.tools import tool
from pydantic import BaseModel, Field

from tools._macos_bridge import bridge_request, get_bridge_config


def _fetch_via_app_api(hours_ahead: int) -> tuple[bool, str]:
    """Fetch calendar events from the Swift app's HTTP API."""
    cfg, cfg_err = get_bridge_config()
    if not cfg:
        return False, (
            "Calendar requires the Mugi app's local bridge (`MUGI_CALENDAR_URL`) with auth token "
            f"(`MUGI_AUTH_TOKEN`). {cfg_err}"
        )

    bounded_hours = min(max(hours_ahead, 1), 168)
    status, raw, err = bridge_request(cfg, f"/calendar/events?hours={bounded_hours}", timeout=15)
    if err:
        low = err.lower()
        if "connection refused" in low or "errno 61" in low:
            return False, "Cannot connect to calendar server. Restart Mugi and try again."
        if "timed out" in low:
            return False, "Calendar server timed out. Ensure Mugi is in the foreground and try again."
        return False, f"Calendar API error: {err}. Try restarting Mugi."
    if not raw:
        return False, f"Calendar API returned HTTP {status} with no data."
    try:
        obj = json.loads(raw.decode("utf-8"))
    except Exception as e:
        return False, f"Calendar API parse error: {e}"
    if status == 200 and obj.get("success"):
        return True, obj.get("formatted", "No events.")
    return False, obj.get("message", f"Calendar API returned HTTP {status}.")


def _fetch_upcoming_events(hours_ahead: int) -> tuple[bool, str]:
    """Fetch events from the user's calendar via the local Swift bridge."""
    return _fetch_via_app_api(hours_ahead)


# ─── Tool: get_upcoming_calendar_events ─────────────────────────────────────────

class GetUpcomingCalendarEventsInput(BaseModel):
    """Input for get_upcoming_calendar_events."""

    hours_ahead: int = Field(
        default=48,
        ge=1,
        le=168,
        description="How many hours ahead to look (1–168). Default 48.",
    )


@tool(args_schema=GetUpcomingCalendarEventsInput)
def get_upcoming_calendar_events(hours_ahead: int = 48) -> str:
    """Get upcoming calendar events from the user's calendar. Use when the user asks what's on their calendar, what meetings they have, or when checking for events during heartbeats (e.g. 'Calendar event coming up'). Returns events in the next N hours. Requires Calendar permission."""
    success, msg = _fetch_upcoming_events(hours_ahead)
    return msg
