# 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

"""
Cal.com Scheduling Skill

Manage availability, bookings, and event types via the Cal.com API v2.

Setup:
    CALCOM_API_KEY=cal_live_...
    CALCOM_URL=https://api.cal.com  (or self-hosted instance URL)

Get a key at: https://app.cal.com/settings/developer/api-keys
API: https://cal.com/docs/api-reference/v2/
"""

import logging

from familiar.core.api_cache import cached
from familiar.skills._api_utils import (
    APIError,
    api_get,
    api_post,
    get_env,
)

logger = logging.getLogger(__name__)


def _api_key() -> str:
    return get_env("CALCOM_API_KEY") or ""


def _base_url() -> str:
    return (get_env("CALCOM_URL") or "https://api.cal.com").rstrip("/")


def _headers() -> dict:
    return {
        "Authorization": f"Bearer {_api_key()}",
        "Content-Type": "application/json",
        "cal-api-version": "2024-08-13",
    }


def _check_config() -> str:
    if not _api_key():
        return (
            "Cal.com not configured.\n"
            "Set CALCOM_API_KEY in your environment.\n"
            "Get a key at: https://app.cal.com/settings/developer/api-keys"
        )
    return ""


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def calcom_availability(data: dict) -> str:
    """Check available time slots."""
    err = _check_config()
    if err:
        return err

    event_type_id = data.get("event_type_id", "")
    start_date = data.get("start_date", "")
    end_date = data.get("end_date", "")

    if not start_date or not end_date:
        return "Please provide start_date and end_date (YYYY-MM-DD)."

    try:
        params = {"start": start_date, "end": end_date}
        if event_type_id:
            params["eventTypeId"] = event_type_id

        result = _availability_cached(start_date, end_date, event_type_id)

        slots = result.get("data", {})
        if not slots:
            return "No available slots found for that period."

        lines = ["**Available Slots:**", ""]

        slot_count = 0
        for date_key, day_slots in sorted(slots.items()):
            if not day_slots:
                continue
            lines.append(f"**{date_key}**")
            for slot in day_slots[:8]:
                start_time = slot.get("start", "")
                end_time = slot.get("end", "")
                if start_time:
                    s = start_time[11:16] if len(start_time) > 16 else start_time
                    e = end_time[11:16] if len(end_time) > 16 else end_time
                    lines.append(f"  {s} - {e}")
                    slot_count += 1
            lines.append("")

        if slot_count == 0:
            return "No available slots found for that period."

        lines.insert(1, f"({slot_count} slots)")
        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cal.com availability error: %s", e)
        return f"Error fetching availability: {e}"


@cached(prefix="calcom_slots", ttl=60)
def _availability_cached(start: str, end: str, event_type_id: str) -> dict:
    params = {"start": start, "end": end}
    if event_type_id:
        params["eventTypeId"] = event_type_id
    return api_get(
        f"{_base_url()}/v2/slots",
        params=params,
        headers=_headers(),
        service_name="Cal.com",
    )


def calcom_bookings(data: dict) -> str:
    """List bookings."""
    err = _check_config()
    if err:
        return err

    status = data.get("status", "")
    limit = min(int(data.get("limit", 20)), 50)

    try:
        result = _bookings_cached(status, limit)

        bookings = result.get("data", [])
        if not bookings:
            return "No bookings found."

        lines = [f"**Bookings** ({len(bookings)}):", ""]

        for i, b in enumerate(bookings, 1):
            title = b.get("title", "Untitled")
            uid = b.get("uid", "")
            bk_status = b.get("status", "")
            start_time = b.get("start", "")[:16] if b.get("start") else ""
            end_time = b.get("end", "")[:16] if b.get("end") else ""
            attendees = b.get("attendees", [])

            lines.append(f"{i}. **{title}** [{bk_status}]")
            details = [f"UID: {uid}"]
            if start_time:
                details.append(f"{start_time} to {end_time}")
            if attendees:
                names = [a.get("name", a.get("email", "")) for a in attendees[:3]]
                details.append(f"Attendees: {', '.join(names)}")
            lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cal.com bookings error: %s", e)
        return f"Error fetching bookings: {e}"


@cached(prefix="calcom_bookings", ttl=60)
def _bookings_cached(status: str, limit: int) -> dict:
    params = {"limit": limit}
    if status:
        params["status"] = status
    return api_get(
        f"{_base_url()}/v2/bookings",
        params=params,
        headers=_headers(),
        service_name="Cal.com",
    )


def calcom_create_event_type(data: dict) -> str:
    """Create a new event type (scheduling template)."""
    err = _check_config()
    if err:
        return err

    title = data.get("title", "").strip()
    if not title:
        return "Please provide a title for the event type."

    length = int(data.get("length_minutes", 30))
    slug = data.get("slug", "").strip() or title.lower().replace(" ", "-")
    description = data.get("description", "")

    try:
        body = {
            "lengthInMinutes": length,
            "title": title,
            "slug": slug,
        }
        if description:
            body["description"] = description

        result = api_post(
            f"{_base_url()}/v2/event-types",
            json=body,
            headers=_headers(),
            service_name="Cal.com",
        )

        et_data = result.get("data", result)
        et_id = et_data.get("id", "")
        booking_url = et_data.get("bookingUrl", "")

        lines = [
            "**Event type created!**",
            "",
            f"  ID: {et_id}",
            f"  Title: {title}",
            f"  Duration: {length} min",
        ]
        if booking_url:
            lines.append(f"  Booking URL: {booking_url}")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cal.com create event type error: %s", e)
        return f"Error creating event type: {e}"


def calcom_cancel(data: dict) -> str:
    """Cancel a booking."""
    err = _check_config()
    if err:
        return err

    booking_uid = data.get("booking_uid", "").strip()
    if not booking_uid:
        return "Please provide a booking_uid to cancel."

    reason = data.get("reason", "")

    try:
        body = {}
        if reason:
            body["cancellationReason"] = reason

        result = api_post(
            f"{_base_url()}/v2/bookings/{booking_uid}/cancel",
            json=body,
            headers=_headers(),
            service_name="Cal.com",
        )

        bk_data = result.get("data", result)
        bk_status = bk_data.get("status", "cancelled")

        return f"**Booking {booking_uid} {bk_status}.**"

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Cal.com cancel error: %s", e)
        return f"Error cancelling booking: {e}"


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "calcom_availability",
        "description": "Check available time slots on Cal.com for a date range.",
        "input_schema": {
            "type": "object",
            "properties": {
                "start_date": {
                    "type": "string",
                    "description": "Start date (YYYY-MM-DD)",
                },
                "end_date": {
                    "type": "string",
                    "description": "End date (YYYY-MM-DD)",
                },
                "event_type_id": {
                    "type": "string",
                    "description": "Filter by event type ID",
                },
            },
            "required": ["start_date", "end_date"],
        },
        "handler": calcom_availability,
        "category": "calcom",
    },
    {
        "name": "calcom_bookings",
        "description": "List Cal.com bookings with attendees and status.",
        "input_schema": {
            "type": "object",
            "properties": {
                "status": {
                    "type": "string",
                    "description": "Filter: accepted, pending, cancelled",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-50, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": calcom_bookings,
        "category": "calcom",
    },
    {
        "name": "calcom_create_event_type",
        "description": "Create a Cal.com event type (scheduling template) with duration and slug.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string", "description": "Event type title"},
                "length_minutes": {
                    "type": "integer",
                    "description": "Duration in minutes (default 30)",
                    "default": 30,
                },
                "slug": {
                    "type": "string",
                    "description": "URL slug (auto-generated from title if omitted)",
                },
                "description": {
                    "type": "string",
                    "description": "Event type description",
                },
            },
            "required": ["title"],
        },
        "handler": calcom_create_event_type,
        "category": "calcom",
    },
    {
        "name": "calcom_cancel",
        "description": "Cancel a Cal.com booking by its UID.",
        "input_schema": {
            "type": "object",
            "properties": {
                "booking_uid": {
                    "type": "string",
                    "description": "Booking UID to cancel",
                },
                "reason": {
                    "type": "string",
                    "description": "Cancellation reason",
                },
            },
            "required": ["booking_uid"],
        },
        "handler": calcom_cancel,
        "category": "calcom",
    },
]
