# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Event Management Skill — full lifecycle event planning.

Built for nonprofit scale (Trans Pride Seattle: 30K+ attendees, 100+ partners).
Tracks events, vendors, volunteers, and milestone timelines with auto-generated
templates per event type.

Stores:
  ~/.familiar/data/events.json
  ~/.familiar/data/event_vendors.json
  ~/.familiar/data/event_volunteers.json
"""

import json
import logging
import os
import secrets
import threading
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)

_lock = threading.Lock()


def _data_dir() -> Path:
    try:
        from familiar.core.paths import DATA_DIR

        return DATA_DIR
    except ImportError:
        return Path.home() / ".familiar" / "data"


# ── Event Types & Milestone Templates ─────────────────────────────────

EVENT_TYPES = [
    "pride_march",
    "gala",
    "fundraiser",
    "workshop",
    "rally",
    "meeting",
    "conference",
    "volunteer_day",
]

EVENT_STATUSES = ["planning", "confirmed", "in_progress", "completed", "cancelled"]

# Milestone templates: list of (name, days_before_event)
# Auto-generated when an event is created with a start_date
MILESTONE_TEMPLATES: dict[str, list[tuple[str, int]]] = {
    "pride_march": [
        ("Form planning committee", 180),
        ("Secure permits & route approval", 150),
        ("Confirm main stage & sound vendor", 120),
        ("Launch volunteer recruitment", 100),
        ("Partner org outreach complete", 90),
        ("Vendor contracts finalized", 75),
        ("Medical & security plan approved", 60),
        ("Marketing campaign launch", 45),
        ("Volunteer training sessions", 30),
        ("Final vendor walk-through", 14),
        ("Day-of briefing & setup", 1),
        ("Post-event debrief & thank-yous", -7),
    ],
    "gala": [
        ("Book venue", 120),
        ("Secure honorary chair / keynote", 100),
        ("Caterer & bar contracts", 90),
        ("Sponsorship outreach complete", 75),
        ("Invitation design & print", 60),
        ("Send invitations", 45),
        ("Auction item collection deadline", 30),
        ("Final RSVPs & seating chart", 14),
        ("Day-of run-of-show finalized", 7),
        ("Post-event donor follow-up", -3),
    ],
    "fundraiser": [
        ("Set fundraising goal & case statement", 90),
        ("Identify & confirm sponsors", 75),
        ("Marketing launch", 60),
        ("Volunteer recruitment", 45),
        ("Mid-campaign check-in", 30),
        ("Final push & peer-to-peer outreach", 14),
        ("Event day logistics confirmed", 7),
        ("Post-event thank-yous & reporting", -7),
    ],
    "workshop": [
        ("Confirm facilitator(s)", 60),
        ("Venue & materials booked", 45),
        ("Promotion & registration open", 30),
        ("Materials prepared & printed", 14),
        ("Participant confirmation emails", 7),
        ("Post-workshop feedback survey", -3),
    ],
    "rally": [
        ("Coalition partners confirmed", 90),
        ("Permits & location secured", 75),
        ("Speaker lineup finalized", 45),
        ("Sound & stage logistics", 30),
        ("Media advisory sent", 14),
        ("Safety plan & marshal briefing", 7),
        ("Day-of setup", 1),
        ("Post-rally media round-up", -3),
    ],
    "meeting": [
        ("Agenda drafted", 14),
        ("Materials prepared", 7),
        ("Reminder sent to attendees", 3),
        ("Post-meeting minutes distributed", -3),
    ],
    "conference": [
        ("Call for proposals opens", 120),
        ("Venue contract signed", 100),
        ("Speaker selection complete", 75),
        ("Registration opens", 60),
        ("Sponsor packets sent", 45),
        ("Schedule published", 30),
        ("AV & catering finalized", 14),
        ("Day-of volunteer briefing", 1),
        ("Post-conference survey & report", -7),
    ],
    "volunteer_day": [
        ("Project scope defined", 45),
        ("Site logistics confirmed", 30),
        ("Volunteer recruitment target met", 21),
        ("Materials & supplies ordered", 14),
        ("Volunteer assignment & briefing", 7),
        ("Post-event impact summary", -3),
    ],
}


# ── EventStore ────────────────────────────────────────────────────────


class EventStore:
    """Thread-safe JSON store for events."""

    def __init__(self):
        self._path = _data_dir() / "events.json"
        self._data: dict = {"events": []}
        self.load()

    def load(self):
        with _lock:
            if self._path.exists():
                try:
                    self._data = json.loads(self._path.read_text())
                except (json.JSONDecodeError, OSError) as e:
                    logger.warning("Failed to load events: %s", e)
                    self._data = {"events": []}
            else:
                self._data = {"events": []}

    def save(self):
        with _lock:
            self._path.parent.mkdir(parents=True, exist_ok=True)
            tmp = self._path.with_suffix(".tmp")
            tmp.write_text(json.dumps(self._data, indent=2))
            tmp.replace(self._path)
            try:
                os.chmod(self._path, 0o600)
            except OSError:
                pass

    def create_event(
        self,
        name: str,
        event_type: str = "meeting",
        start_date: str = "",
        end_date: str = "",
        status: str = "planning",
        venue: Optional[dict] = None,
        budget_total: float = 0,
        description: str = "",
        partner_orgs: Optional[list] = None,
        volunteer_slots_total: int = 0,
        auto_milestones: bool = True,
    ) -> str:
        """Create an event. Returns event_id."""
        event_id = f"ev_{secrets.token_hex(6)}"
        now = datetime.now(timezone.utc).isoformat()

        event = {
            "id": event_id,
            "name": name,
            "event_type": event_type if event_type in EVENT_TYPES else "meeting",
            "start_date": start_date,
            "end_date": end_date or start_date,
            "status": status if status in EVENT_STATUSES else "planning",
            "venue": venue or {},
            "budget_total": budget_total,
            "budget_spent": 0,
            "description": description,
            "partner_orgs": partner_orgs or [],
            "volunteer_slots_total": volunteer_slots_total,
            "volunteers_assigned": 0,
            "milestones": [],
            "created_at": now,
            "updated_at": now,
        }

        # Auto-generate milestones if start_date is set
        if auto_milestones and start_date:
            event["milestones"] = _generate_milestones(event_type, start_date)

        self._data["events"].append(event)
        self.save()
        return event_id

    def get_event(self, event_id: str) -> Optional[dict]:
        self.load()
        for e in self._data["events"]:
            if e["id"] == event_id:
                return e
        return None

    def list_events(self, status: Optional[str] = None) -> list[dict]:
        self.load()
        events = self._data["events"]
        if status:
            events = [e for e in events if e.get("status") == status]
        events.sort(key=lambda e: e.get("start_date", ""))
        return events

    def update_event(self, event_id: str, updates: dict) -> Optional[dict]:
        for e in self._data["events"]:
            if e["id"] == event_id:
                for k, v in updates.items():
                    if k not in ("id", "created_at"):
                        e[k] = v
                e["updated_at"] = datetime.now(timezone.utc).isoformat()
                self.save()
                return e
        return None

    def delete_event(self, event_id: str) -> bool:
        before = len(self._data["events"])
        self._data["events"] = [e for e in self._data["events"] if e["id"] != event_id]
        if len(self._data["events"]) < before:
            self.save()
            return True
        return False

    def update_milestone(self, event_id: str, milestone_index: int, status: str) -> Optional[dict]:
        """Update a milestone's status by 0-based index."""
        event = self.get_event(event_id)
        if not event:
            return None
        milestones = event.get("milestones", [])
        if 0 <= milestone_index < len(milestones):
            milestones[milestone_index]["status"] = status
            if status == "done":
                milestones[milestone_index]["completed_at"] = datetime.now(timezone.utc).isoformat()
            self.save()
            return milestones[milestone_index]
        return None

    def get_upcoming_milestones(self, days: int = 7) -> list[dict]:
        """Get milestones due within N days across all events."""
        self.load()
        today = datetime.now(timezone.utc).date()
        cutoff = today + timedelta(days=days)
        results = []
        for event in self._data["events"]:
            if event.get("status") in ("completed", "cancelled"):
                continue
            for i, m in enumerate(event.get("milestones", [])):
                if m.get("status") == "done":
                    continue
                due = m.get("due_date", "")
                if not due:
                    continue
                try:
                    due_date = datetime.fromisoformat(due).date()
                    if due_date <= cutoff:
                        results.append(
                            {
                                "event_id": event["id"],
                                "event_name": event["name"],
                                "milestone_index": i,
                                "milestone_name": m["name"],
                                "due_date": due,
                                "overdue": due_date < today,
                            }
                        )
                except ValueError:
                    continue
        results.sort(key=lambda m: m["due_date"])
        return results

    def count_upcoming(self) -> int:
        """Count events with status in (planning, confirmed, in_progress)."""
        self.load()
        return sum(
            1
            for e in self._data["events"]
            if e.get("status") in ("planning", "confirmed", "in_progress")
        )


def _generate_milestones(event_type: str, start_date: str) -> list[dict]:
    """Generate milestone list from templates for the given event type."""
    templates = MILESTONE_TEMPLATES.get(event_type, MILESTONE_TEMPLATES.get("meeting", []))
    try:
        base = datetime.fromisoformat(start_date)
    except ValueError:
        return []

    milestones = []
    for name, days_before in templates:
        due = base - timedelta(days=days_before)
        milestones.append(
            {
                "name": name,
                "due_date": due.strftime("%Y-%m-%d"),
                "status": "pending",
                "assignee": "",
                "completed_at": None,
            }
        )
    return milestones


def get_event_store() -> EventStore:
    return EventStore()


# ── VendorStore ───────────────────────────────────────────────────────

VENDOR_SERVICE_TYPES = [
    "catering",
    "sound",
    "staging",
    "security",
    "medical",
    "transport",
    "photography",
    "printing",
    "decor",
    "other",
]

CONTRACT_STATUSES = ["inquired", "quoted", "contracted", "paid", "cancelled"]


class VendorStore:
    """Thread-safe JSON store for event vendors."""

    def __init__(self):
        self._path = _data_dir() / "event_vendors.json"
        self._data: dict = {"vendors": []}
        self.load()

    def load(self):
        with _lock:
            if self._path.exists():
                try:
                    self._data = json.loads(self._path.read_text())
                except (json.JSONDecodeError, OSError) as e:
                    logger.warning("Failed to load vendors: %s", e)
                    self._data = {"vendors": []}
            else:
                self._data = {"vendors": []}

    def save(self):
        with _lock:
            self._path.parent.mkdir(parents=True, exist_ok=True)
            tmp = self._path.with_suffix(".tmp")
            tmp.write_text(json.dumps(self._data, indent=2))
            tmp.replace(self._path)
            try:
                os.chmod(self._path, 0o600)
            except OSError:
                pass

    def add_vendor(
        self,
        event_id: str,
        name: str,
        service_type: str = "other",
        contact_name: str = "",
        contact_email: str = "",
        contact_phone: str = "",
        quote_amount: float = 0,
        notes: str = "",
    ) -> str:
        vendor_id = f"vn_{secrets.token_hex(6)}"
        self._data["vendors"].append(
            {
                "id": vendor_id,
                "event_id": event_id,
                "name": name,
                "service_type": service_type if service_type in VENDOR_SERVICE_TYPES else "other",
                "contact_name": contact_name,
                "contact_email": contact_email,
                "contact_phone": contact_phone,
                "contract_status": "inquired",
                "quote_amount": quote_amount,
                "paid_amount": 0,
                "notes": notes,
                "insurance_verified": False,
                "created_at": datetime.now(timezone.utc).isoformat(),
            }
        )
        self.save()
        return vendor_id

    def list_vendors(self, event_id: Optional[str] = None) -> list[dict]:
        self.load()
        vendors = self._data["vendors"]
        if event_id:
            vendors = [v for v in vendors if v["event_id"] == event_id]
        return vendors

    def update_vendor(self, vendor_id: str, updates: dict) -> Optional[dict]:
        for v in self._data["vendors"]:
            if v["id"] == vendor_id:
                for k, val in updates.items():
                    if k not in ("id", "event_id", "created_at"):
                        v[k] = val
                self.save()
                return v
        return None

    def delete_vendor(self, vendor_id: str) -> bool:
        before = len(self._data["vendors"])
        self._data["vendors"] = [v for v in self._data["vendors"] if v["id"] != vendor_id]
        if len(self._data["vendors"]) < before:
            self.save()
            return True
        return False


def get_vendor_store() -> VendorStore:
    return VendorStore()


# ── VolunteerStore ────────────────────────────────────────────────────

VOLUNTEER_ROLES = [
    "setup",
    "registration",
    "security",
    "medical",
    "cleanup",
    "coordinator",
    "marshal",
    "other",
]


class VolunteerStore:
    """Thread-safe JSON store for event volunteers."""

    def __init__(self):
        self._path = _data_dir() / "event_volunteers.json"
        self._data: dict = {"volunteers": []}
        self.load()

    def load(self):
        with _lock:
            if self._path.exists():
                try:
                    self._data = json.loads(self._path.read_text())
                except (json.JSONDecodeError, OSError) as e:
                    logger.warning("Failed to load volunteers: %s", e)
                    self._data = {"volunteers": []}
            else:
                self._data = {"volunteers": []}

    def save(self):
        with _lock:
            self._path.parent.mkdir(parents=True, exist_ok=True)
            tmp = self._path.with_suffix(".tmp")
            tmp.write_text(json.dumps(self._data, indent=2))
            tmp.replace(self._path)
            try:
                os.chmod(self._path, 0o600)
            except OSError:
                pass

    def add_volunteer(
        self,
        event_id: str,
        name: str,
        email: str = "",
        phone: str = "",
        role: str = "other",
        shift_start: str = "",
        shift_end: str = "",
        notes: str = "",
    ) -> str:
        vol_id = f"vol_{secrets.token_hex(6)}"
        self._data["volunteers"].append(
            {
                "id": vol_id,
                "event_id": event_id,
                "name": name,
                "email": email,
                "phone": phone,
                "role": role if role in VOLUNTEER_ROLES else "other",
                "shift_start": shift_start,
                "shift_end": shift_end,
                "checked_in": False,
                "checked_in_at": None,
                "notes": notes,
                "created_at": datetime.now(timezone.utc).isoformat(),
            }
        )
        self.save()
        return vol_id

    def list_volunteers(self, event_id: Optional[str] = None) -> list[dict]:
        self.load()
        vols = self._data["volunteers"]
        if event_id:
            vols = [v for v in vols if v["event_id"] == event_id]
        return vols

    def check_in(self, volunteer_id: str) -> bool:
        for v in self._data["volunteers"]:
            if v["id"] == volunteer_id:
                v["checked_in"] = True
                v["checked_in_at"] = datetime.now(timezone.utc).isoformat()
                self.save()
                return True
        return False

    def summary_by_role(self, event_id: str) -> dict[str, int]:
        """Count volunteers by role for an event."""
        counts: dict[str, int] = {}
        for v in self.list_volunteers(event_id):
            r = v.get("role", "other")
            counts[r] = counts.get(r, 0) + 1
        return counts

    def delete_volunteer(self, volunteer_id: str) -> bool:
        before = len(self._data["volunteers"])
        self._data["volunteers"] = [v for v in self._data["volunteers"] if v["id"] != volunteer_id]
        if len(self._data["volunteers"]) < before:
            self.save()
            return True
        return False


def get_volunteer_store() -> VolunteerStore:
    return VolunteerStore()


# ── Tool Handlers ─────────────────────────────────────────────────────


def create_event(params: dict) -> str:
    """Create a new event with optional auto-generated milestones."""
    name = params.get("name", "").strip()
    if not name:
        return "Error: event name is required."

    store = get_event_store()
    event_id = store.create_event(
        name=name,
        event_type=params.get("event_type", "meeting"),
        start_date=params.get("start_date", ""),
        end_date=params.get("end_date", ""),
        status=params.get("status", "planning"),
        venue=params.get("venue"),
        budget_total=float(params.get("budget_total", 0)),
        description=params.get("description", ""),
        partner_orgs=params.get("partner_orgs"),
        volunteer_slots_total=int(params.get("volunteer_slots_total", 0)),
        auto_milestones=params.get("auto_milestones", True),
    )

    event = store.get_event(event_id)
    milestone_count = len(event.get("milestones", []))
    result = f"Created event '{name}' ({event_id})"
    if milestone_count:
        result += f" with {milestone_count} auto-generated milestones"
    return result + "."


def list_events(params: dict) -> str:
    """List events, optionally filtered by status."""
    store = get_event_store()
    events = store.list_events(status=params.get("status"))
    if not events:
        return "No events found."

    lines = [f"**{len(events)} Events:**\n"]
    for e in events:
        budget = f"${e['budget_total']:,.0f}" if e.get("budget_total") else "no budget"
        milestones = e.get("milestones", [])
        done = sum(1 for m in milestones if m.get("status") == "done")
        lines.append(
            f"- **{e['name']}** ({e['event_type']}) — {e['status']}"
            f" | {e.get('start_date', 'TBD')} | {budget}"
            f" | milestones: {done}/{len(milestones)}"
        )
    return "\n".join(lines)


def event_details(params: dict) -> str:
    """Show detailed event info including milestones."""
    event_id = params.get("event_id", "")
    store = get_event_store()
    e = store.get_event(event_id)
    if not e:
        return f"Event '{event_id}' not found."

    lines = [
        f"# {e['name']}",
        f"**Type:** {e['event_type']} | **Status:** {e['status']}",
        f"**Dates:** {e.get('start_date', 'TBD')} to {e.get('end_date', 'TBD')}",
    ]

    venue = e.get("venue", {})
    if venue:
        lines.append(
            f"**Venue:** {venue.get('name', 'TBD')}"
            f" ({venue.get('address', '')})"
            f" — capacity: {venue.get('capacity', '?')}"
        )

    lines.append(
        f"**Budget:** ${e.get('budget_total', 0):,.0f} (spent: ${e.get('budget_spent', 0):,.0f})"
    )

    partners = e.get("partner_orgs", [])
    if partners:
        lines.append(f"**Partners:** {', '.join(partners)}")

    lines.append(
        f"**Volunteers:** {e.get('volunteers_assigned', 0)} / {e.get('volunteer_slots_total', 0)}"
    )

    milestones = e.get("milestones", [])
    if milestones:
        lines.append(f"\n## Milestones ({len(milestones)})")
        for i, m in enumerate(milestones):
            icon = "done" if m["status"] == "done" else "pending"
            assignee = f" ({m['assignee']})" if m.get("assignee") else ""
            lines.append(f"{i + 1}. [{icon}] {m['name']} — due {m['due_date']}{assignee}")

    return "\n".join(lines)


def update_event(params: dict) -> str:
    """Update an event's fields."""
    event_id = params.get("event_id", "")
    if not event_id:
        return "Error: event_id is required."

    store = get_event_store()
    updates = {k: v for k, v in params.items() if k != "event_id"}
    result = store.update_event(event_id, updates)
    if result:
        return f"Updated event '{result['name']}'."
    return f"Event '{event_id}' not found."


def delete_event(params: dict) -> str:
    """Delete an event."""
    event_id = params.get("event_id", "")
    store = get_event_store()
    if store.delete_event(event_id):
        return f"Deleted event {event_id}."
    return f"Event '{event_id}' not found."


def update_milestone(params: dict) -> str:
    """Update a milestone's status (pending/in_progress/done)."""
    event_id = params.get("event_id", "")
    index = int(params.get("milestone_index", -1))
    status = params.get("status", "done")

    store = get_event_store()
    result = store.update_milestone(event_id, index, status)
    if result:
        return f"Milestone '{result['name']}' marked as {status}."
    return "Milestone not found. Check event_id and milestone_index."


def event_timeline(params: dict) -> str:
    """Show milestone timeline for an event with urgency indicators."""
    event_id = params.get("event_id", "")
    store = get_event_store()
    e = store.get_event(event_id)
    if not e:
        return f"Event '{event_id}' not found."

    milestones = e.get("milestones", [])
    if not milestones:
        return f"No milestones for '{e['name']}'."

    today = datetime.now(timezone.utc).date()
    lines = [f"## Timeline: {e['name']}\n"]
    for i, m in enumerate(milestones):
        due = m.get("due_date", "")
        status = m.get("status", "pending")
        if status == "done":
            indicator = "[DONE]"
        elif due:
            try:
                due_date = datetime.fromisoformat(due).date()
                days_left = (due_date - today).days
                if days_left < 0:
                    indicator = f"[OVERDUE by {-days_left}d]"
                elif days_left <= 7:
                    indicator = f"[DUE in {days_left}d]"
                else:
                    indicator = f"[{days_left}d away]"
            except ValueError:
                indicator = "[pending]"
        else:
            indicator = "[pending]"

        lines.append(f"{i + 1}. {indicator} {m['name']} — {due}")

    return "\n".join(lines)


def add_vendor(params: dict) -> str:
    """Add a vendor to an event."""
    event_id = params.get("event_id", "")
    name = params.get("name", "").strip()
    if not name:
        return "Error: vendor name is required."

    store = get_vendor_store()
    vendor_id = store.add_vendor(
        event_id=event_id,
        name=name,
        service_type=params.get("service_type", "other"),
        contact_name=params.get("contact_name", ""),
        contact_email=params.get("contact_email", ""),
        contact_phone=params.get("contact_phone", ""),
        quote_amount=float(params.get("quote_amount", 0)),
        notes=params.get("notes", ""),
    )
    return f"Added vendor '{name}' ({vendor_id}) to event {event_id}."


def list_vendors(params: dict) -> str:
    """List vendors, optionally filtered by event."""
    store = get_vendor_store()
    vendors = store.list_vendors(event_id=params.get("event_id"))
    if not vendors:
        return "No vendors found."

    lines = [f"**{len(vendors)} Vendors:**\n"]
    for v in vendors:
        quote = f"${v['quote_amount']:,.0f}" if v.get("quote_amount") else "no quote"
        lines.append(
            f"- **{v['name']}** ({v['service_type']}) — {v['contract_status']}"
            f" | {quote} | insurance: {'yes' if v.get('insurance_verified') else 'no'}"
        )
    return "\n".join(lines)


def update_vendor(params: dict) -> str:
    """Update vendor details."""
    vendor_id = params.get("vendor_id", "")
    store = get_vendor_store()
    updates = {k: v for k, v in params.items() if k != "vendor_id"}
    result = store.update_vendor(vendor_id, updates)
    if result:
        return f"Updated vendor '{result['name']}'."
    return f"Vendor '{vendor_id}' not found."


def add_volunteer(params: dict) -> str:
    """Add a volunteer to an event."""
    event_id = params.get("event_id", "")
    name = params.get("name", "").strip()
    if not name:
        return "Error: volunteer name is required."

    store = get_volunteer_store()
    vol_id = store.add_volunteer(
        event_id=event_id,
        name=name,
        email=params.get("email", ""),
        phone=params.get("phone", ""),
        role=params.get("role", "other"),
        shift_start=params.get("shift_start", ""),
        shift_end=params.get("shift_end", ""),
        notes=params.get("notes", ""),
    )
    return f"Added volunteer '{name}' ({vol_id}) to event {event_id}."


def list_volunteers(params: dict) -> str:
    """List volunteers, optionally filtered by event."""
    store = get_volunteer_store()
    vols = store.list_volunteers(event_id=params.get("event_id"))
    if not vols:
        return "No volunteers found."

    lines = [f"**{len(vols)} Volunteers:**\n"]
    for v in vols:
        checked = "checked in" if v.get("checked_in") else "not checked in"
        lines.append(
            f"- **{v['name']}** ({v['role']}) — {checked}"
            f" | shift: {v.get('shift_start', '?')} - {v.get('shift_end', '?')}"
        )
    return "\n".join(lines)


def check_in_volunteer(params: dict) -> str:
    """Check in a volunteer."""
    vol_id = params.get("volunteer_id", "")
    store = get_volunteer_store()
    if store.check_in(vol_id):
        return f"Volunteer {vol_id} checked in."
    return f"Volunteer '{vol_id}' not found."


def volunteer_summary(params: dict) -> str:
    """Summarize volunteers by role for an event."""
    event_id = params.get("event_id", "")
    store = get_volunteer_store()
    counts = store.summary_by_role(event_id)
    if not counts:
        return f"No volunteers for event {event_id}."

    total = sum(counts.values())
    lines = [f"**Volunteer Summary ({total} total):**\n"]
    for role, count in sorted(counts.items(), key=lambda x: -x[1]):
        lines.append(f"- {role}: {count}")
    return "\n".join(lines)


# ── Tool Definitions ──────────────────────────────────────────────────

TOOLS = [
    {
        "name": "create_event",
        "description": (
            "Create a new event (gala, fundraiser, pride march, workshop, rally,"
            " meeting, conference, volunteer day). Auto-generates milestone"
            " timeline based on event type and start date."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Event name"},
                "event_type": {
                    "type": "string",
                    "enum": EVENT_TYPES,
                    "description": "Type of event",
                },
                "start_date": {
                    "type": "string",
                    "description": "Start date (YYYY-MM-DD or ISO)",
                },
                "end_date": {"type": "string", "description": "End date"},
                "description": {"type": "string"},
                "budget_total": {"type": "number"},
                "volunteer_slots_total": {"type": "integer"},
                "venue": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "address": {"type": "string"},
                        "capacity": {"type": "integer"},
                        "cost": {"type": "number"},
                    },
                },
                "partner_orgs": {
                    "type": "array",
                    "items": {"type": "string"},
                },
            },
            "required": ["name"],
        },
        "handler": create_event,
    },
    {
        "name": "list_events",
        "description": "List all events, optionally filtered by status.",
        "input_schema": {
            "type": "object",
            "properties": {
                "status": {
                    "type": "string",
                    "enum": EVENT_STATUSES,
                },
            },
        },
        "handler": list_events,
    },
    {
        "name": "event_details",
        "description": "Show detailed event info including milestones, budget, and venue.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
            "required": ["event_id"],
        },
        "handler": event_details,
    },
    {
        "name": "update_event",
        "description": "Update an event's fields (status, dates, budget, venue, etc).",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
                "name": {"type": "string"},
                "status": {"type": "string", "enum": EVENT_STATUSES},
                "start_date": {"type": "string"},
                "end_date": {"type": "string"},
                "budget_total": {"type": "number"},
                "description": {"type": "string"},
            },
            "required": ["event_id"],
        },
        "handler": update_event,
    },
    {
        "name": "delete_event",
        "description": "Delete an event.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
            "required": ["event_id"],
        },
        "handler": delete_event,
    },
    {
        "name": "update_milestone",
        "description": "Update a milestone's status (pending/in_progress/done).",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
                "milestone_index": {"type": "integer", "description": "0-based index"},
                "status": {
                    "type": "string",
                    "enum": ["pending", "in_progress", "done"],
                },
            },
            "required": ["event_id", "milestone_index"],
        },
        "handler": update_milestone,
    },
    {
        "name": "event_timeline",
        "description": (
            "Show milestone timeline for an event with urgency indicators"
            " (overdue, due soon, days remaining)."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
            "required": ["event_id"],
        },
        "handler": event_timeline,
    },
    {
        "name": "add_vendor",
        "description": "Add a vendor to an event (catering, sound, staging, etc).",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
                "name": {"type": "string"},
                "service_type": {
                    "type": "string",
                    "enum": VENDOR_SERVICE_TYPES,
                },
                "contact_name": {"type": "string"},
                "contact_email": {"type": "string"},
                "quote_amount": {"type": "number"},
            },
            "required": ["event_id", "name"],
        },
        "handler": add_vendor,
    },
    {
        "name": "list_vendors",
        "description": "List vendors for an event.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
        },
        "handler": list_vendors,
    },
    {
        "name": "update_vendor",
        "description": "Update vendor details (contract status, payment, insurance).",
        "input_schema": {
            "type": "object",
            "properties": {
                "vendor_id": {"type": "string"},
                "contract_status": {
                    "type": "string",
                    "enum": CONTRACT_STATUSES,
                },
                "paid_amount": {"type": "number"},
                "insurance_verified": {"type": "boolean"},
                "notes": {"type": "string"},
            },
            "required": ["vendor_id"],
        },
        "handler": update_vendor,
    },
    {
        "name": "add_volunteer",
        "description": "Add a volunteer to an event with role and shift.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
                "name": {"type": "string"},
                "email": {"type": "string"},
                "role": {"type": "string", "enum": VOLUNTEER_ROLES},
                "shift_start": {"type": "string"},
                "shift_end": {"type": "string"},
            },
            "required": ["event_id", "name"],
        },
        "handler": add_volunteer,
    },
    {
        "name": "list_volunteers",
        "description": "List volunteers for an event.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
        },
        "handler": list_volunteers,
    },
    {
        "name": "check_in_volunteer",
        "description": "Check in a volunteer at the event.",
        "input_schema": {
            "type": "object",
            "properties": {
                "volunteer_id": {"type": "string"},
            },
            "required": ["volunteer_id"],
        },
        "handler": check_in_volunteer,
    },
    {
        "name": "volunteer_summary",
        "description": "Summary of volunteers by role for an event.",
        "input_schema": {
            "type": "object",
            "properties": {
                "event_id": {"type": "string"},
            },
            "required": ["event_id"],
        },
        "handler": volunteer_summary,
    },
]
