"""iCalendar generation for the Add-to-Calendar action (task 2.9, FR-1.8).

Hand-rolled rather than pulled from a library: the payload is a dozen lines of a stable
format, and the escaping rules are the only subtle part.
"""

from datetime import UTC, datetime, timedelta
from urllib.parse import quote

ICS_TIME_FORMAT = "%Y%m%dT%H%M%SZ"
DEFAULT_DURATION = timedelta(hours=3)


def _escape(value: str) -> str:
    """RFC 5545 §3.3.11: backslash, semicolon, comma and newline are special."""
    return value.replace("\\", "\\\\").replace(";", "\\;").replace(",", "\\,").replace("\n", "\\n")


def _fold(line: str, limit: int = 73) -> list[str]:
    """Lines wrap at 75 octets; continuations begin with a single space."""
    if len(line) <= limit:
        return [line]
    parts = [line[:limit]]
    rest = line[limit:]
    while rest:
        parts.append(" " + rest[: limit - 1])
        rest = rest[limit - 1 :]
    return parts


def build_ics(
    *,
    uid: str,
    summary: str,
    description: str,
    location: str,
    starts_at: datetime,
    ends_at: datetime | None = None,
    url: str | None = None,
) -> str:
    end = ends_at or (starts_at + DEFAULT_DURATION)
    now = datetime.now(UTC)

    lines = [
        "BEGIN:VCALENDAR",
        "VERSION:2.0",
        "PRODID:-//Wedding RSVP//EN",
        "CALSCALE:GREGORIAN",
        "METHOD:PUBLISH",
        "BEGIN:VEVENT",
        f"UID:{uid}",
        f"DTSTAMP:{now.strftime(ICS_TIME_FORMAT)}",
        f"DTSTART:{starts_at.astimezone(UTC).strftime(ICS_TIME_FORMAT)}",
        f"DTEND:{end.astimezone(UTC).strftime(ICS_TIME_FORMAT)}",
        f"SUMMARY:{_escape(summary)}",
        f"DESCRIPTION:{_escape(description)}",
        f"LOCATION:{_escape(location)}",
    ]
    if url:
        lines.append(f"URL:{_escape(url)}")
    lines += ["STATUS:CONFIRMED", "END:VEVENT", "END:VCALENDAR"]

    folded: list[str] = []
    for line in lines:
        folded.extend(_fold(line))
    # CRLF is required by the spec, and some calendar clients genuinely reject bare LF.
    return "\r\n".join(folded) + "\r\n"


def google_calendar_url(
    *,
    summary: str,
    details: str,
    location: str,
    starts_at: datetime,
    ends_at: datetime | None = None,
) -> str:
    """Google Calendar's template URL, for guests who prefer a link to a download."""
    end = ends_at or (starts_at + DEFAULT_DURATION)
    dates = (
        f"{starts_at.astimezone(UTC).strftime(ICS_TIME_FORMAT)}"
        f"/{end.astimezone(UTC).strftime(ICS_TIME_FORMAT)}"
    )
    return (
        "https://calendar.google.com/calendar/render?action=TEMPLATE"
        f"&text={quote(summary)}"
        f"&dates={dates}"
        f"&details={quote(details)}"
        f"&location={quote(location)}"
    )
