import { createHash, randomBytes } from "node:crypto";

export interface CalendarFeedEntry {
  uid: string;
  title: string;
  description?: string | null;
  start: string;
  end: string;
  allDay?: boolean;
  updatedAt?: string | null;
}

function escapeIcsText(value: string) {
  return value
    .replace(/\\/g, "\\\\")
    .replace(/\r?\n/g, "\\n")
    .replace(/,/g, "\\,")
    .replace(/;/g, "\\;");
}

function formatUtcDateTime(value: string) {
  return new Date(value).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
}

function formatAllDayDate(value: string) {
  return new Date(value).toISOString().slice(0, 10).replace(/-/g, "");
}

function addDays(value: string, days: number) {
  const next = new Date(value);
  next.setUTCDate(next.getUTCDate() + days);
  return next.toISOString();
}

function renderEvent(entry: CalendarFeedEntry) {
  const lines = [
    "BEGIN:VEVENT",
    `UID:${escapeIcsText(entry.uid)}`,
    `DTSTAMP:${formatUtcDateTime(entry.updatedAt || new Date().toISOString())}`,
    `SUMMARY:${escapeIcsText(entry.title)}`,
  ];

  if (entry.description) {
    lines.push(`DESCRIPTION:${escapeIcsText(entry.description)}`);
  }

  if (entry.allDay) {
    lines.push(`DTSTART;VALUE=DATE:${formatAllDayDate(entry.start)}`);
    lines.push(`DTEND;VALUE=DATE:${formatAllDayDate(addDays(entry.end || entry.start, 1))}`);
  } else {
    lines.push(`DTSTART:${formatUtcDateTime(entry.start)}`);
    lines.push(`DTEND:${formatUtcDateTime(entry.end)}`);
  }

  lines.push("END:VEVENT");
  return lines.join("\r\n");
}

export function createCalendarFeedToken() {
  return `mbcal_${randomBytes(24).toString("base64url")}`;
}

export function hashCalendarFeedToken(token: string) {
  return createHash("sha256").update(token).digest("hex");
}

export function getCalendarFeedTokenPrefix(token: string) {
  return token.slice(0, 12);
}

export function buildCalendarFeedUrl(origin: string, token: string) {
  return `${origin.replace(/\/$/, "")}/api/integrations/calendar-feed/${token}`;
}

export function buildWorkspaceCalendarFeed(input: {
  calendarName: string;
  entries: CalendarFeedEntry[];
}) {
  const lines = [
    "BEGIN:VCALENDAR",
    "VERSION:2.0",
    "PRODID:-//Mindavio//Workspace Calendar//EN",
    "CALSCALE:GREGORIAN",
    "METHOD:PUBLISH",
    `X-WR-CALNAME:${escapeIcsText(input.calendarName)}`,
    ...input.entries.map(renderEvent),
    "END:VCALENDAR",
  ];

  return `${lines.join("\r\n")}\r\n`;
}
