# tools/reminders_tools.py — Agent tools for reading and creating Apple Reminders.
# When MUGI_CALENDAR_URL is set (Swift app context), fetches from the app's EventKit-backed
# HTTP endpoint (/reminders/list, /reminders/add) so the permission prompt shows with Mugi's identity.
from __future__ import annotations

import json
from datetime import datetime, timedelta

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

from tools._macos_bridge import bridge_request_json, get_bridge_config


def _get(path: str) -> tuple[bool, str]:
    cfg, cfg_err = get_bridge_config()
    if not cfg:
        return False, f"Reminders API not available: {cfg_err}"
    status, obj, err = bridge_request_json(cfg, path, method="GET", timeout=15)
    if err:
        low = err.lower()
        if "connection refused" in low:
            return False, "Cannot connect to Mugi's local server. Restart Mugi and try again."
        return False, f"Reminders API error: {err}"
    obj = obj or {}
    if status == 200 and obj.get("success"):
        return True, obj.get("formatted", "")
    return False, obj.get("message", f"HTTP {status}")


def _post(path: str, payload: dict) -> tuple[bool, str]:
    cfg, cfg_err = get_bridge_config()
    if not cfg:
        return False, f"Reminders API not available: {cfg_err}"
    status, obj, err = bridge_request_json(cfg, path, method="POST", payload=payload, timeout=15)
    if err:
        return False, f"Reminders API error: {err}"
    obj = obj or {}
    if status == 200 and obj.get("success"):
        return True, obj.get("message", "Done.")
    return False, obj.get("message", f"HTTP {status}")


class GetRemindersInput(BaseModel):
    incomplete_only: bool = Field(default=True, description="Only return incomplete (not yet done) reminders.")
    due_within_hours: int = Field(default=24, ge=0, le=8760, description="Only return reminders due within this many hours. 0 means all reminders (no due-date filter).")


@tool(args_schema=GetRemindersInput)
def get_reminders(incomplete_only: bool = True, due_within_hours: int = 24) -> str:
    """Get reminders from Apple Reminders. Returns due/overdue reminders grouped by urgency. Use during heartbeats or when the user asks 'what do I need to do?', 'any reminders?', or 'what's due today?'. Requires Reminders permission (grant in Settings → Access → Reminders)."""
    params: dict[str, str] = {}
    if not incomplete_only:
        params["incomplete"] = "0"
    if due_within_hours and due_within_hours > 0:
        params["due_within_hours"] = str(due_within_hours)
    qs = ("?" + "&".join(f"{k}={v}" for k, v in params.items())) if params else ""
    success, msg = _get(f"/reminders/list{qs}")
    return msg


class AddReminderInput(BaseModel):
    title: str = Field(description="The reminder title / text.")
    due_date: str = Field(default="", description="Optional due date in ISO 8601 format (e.g. '2025-03-05T09:00:00'). Leave empty for no due date.")
    list_name: str = Field(default="", description="Optional name of the Reminders list to add to (e.g. 'Work'). Defaults to the default list.")
    notes: str = Field(default="", description="Optional notes to attach to the reminder.")


@tool(args_schema=AddReminderInput)
def add_reminder(title: str, due_date: str = "", list_name: str = "", notes: str = "") -> str:
    """Add a new reminder to Apple Reminders. Use when the user says 'remind me to X', 'add a reminder for Y', or 'set a reminder for Z at time T'. Requires Reminders full access (grant in Settings → Access → Reminders)."""
    payload: dict = {"title": title.strip()}
    if due_date.strip():
        payload["due_date"] = due_date.strip()
    if list_name.strip():
        payload["list_name"] = list_name.strip()
    if notes.strip():
        payload["notes"] = notes.strip()
    success, msg = _post("/reminders/add", payload)
    return msg


@tool
def remind_me_in(minutes: int, message: str) -> str:
    """Set a one-off reminder that fires in N minutes. Use when the user says 'remind me in 20 minutes', 'ping me in an hour', or 'remind me in 30 min to X'. Creates an Apple Reminder with a due date so you get a notification at that time."""
    if minutes < 1:
        return "Minutes must be at least 1."
    if minutes > 40320:  # 28 days
        return "Minutes must be at most 40320 (28 days). Use add_reminder with a due_date for longer."
    due = datetime.now() + timedelta(minutes=minutes)
    iso = due.strftime("%Y-%m-%dT%H:%M:%S")
    return add_reminder.invoke({"title": message.strip() or "Reminder", "due_date": iso, "list_name": "", "notes": ""})


@tool
def remind_at(iso_time: str, message: str) -> str:
    """Set a one-off reminder for a specific date and time. Use when the user says 'remind me at 3pm', 'remind me tomorrow at 9am', or 'remind me on Friday at noon'. Pass the target time in ISO 8601 format (e.g. 2025-03-05T15:00:00). Use get_current_time to know today's date and build the correct ISO string."""
    iso_time = (iso_time or "").strip()
    if not iso_time:
        return "Provide the reminder time in ISO 8601 format (e.g. 2025-03-05T15:00:00). Use get_current_time to get today's date."
    return add_reminder.invoke({"title": message.strip() or "Reminder", "due_date": iso_time, "list_name": "", "notes": ""})
