import ICAL from "ical.js";
import type { CalendarEvent } from "@/lib/types";
import {
	isBinary,
	isDuration,
	isPeriod,
	isRecur,
	isTime,
	isUtcOffset,
} from "./ical-helpers";

function safeValueToString(
	val: ReturnType<ICAL.Component["getFirstPropertyValue"]>,
): string | undefined {
	if (val === undefined) return undefined;
	if (typeof val === "string") return val;
	if (isTime(val)) return val.toJSDate().toISOString();
	if (isRecur(val)) return val.toString();
	if (isUtcOffset(val)) return val.toString(); // already "±HHMM"
	if (isBinary(val) || isDuration(val) || isPeriod(val)) return val.toString();
	return undefined;
}

export function parseICS(icsString: string): CalendarEvent[] {
	const jcalData = ICAL.parse(icsString);
	const comp = new ICAL.Component(jcalData);
	const vevents = comp.getAllSubcomponents("vevent");

	return vevents.map((v) => {
		const ev = new ICAL.Event(v);

		return {
			id: ev.uid || crypto.randomUUID(),
			title: ev.summary || "Untitled Event",
			description: ev.description || "",
			location: ev.location || "",
			url: safeValueToString(v.getFirstPropertyValue("url")),
			start: ev.startDate.toJSDate().toISOString(),
			end: ev.endDate ? ev.endDate.toJSDate().toISOString() : undefined,
			allDay: ev.startDate.isDate,
			createdAt: safeValueToString(v.getFirstPropertyValue("dtstamp")),
			lastModified: safeValueToString(v.getFirstPropertyValue("last-modified")),
			recurrenceRule: safeValueToString(v.getFirstPropertyValue("rrule")),
		};
	});
}

export function generateICS(events: CalendarEvent[]): string {
	const comp = new ICAL.Component(["vcalendar", [], []]);
	comp.addPropertyWithValue("version", "2.0");
	comp.addPropertyWithValue("prodid", "-//iCalPWA//EN");

	events.forEach((ev) => {
		const vevent = new ICAL.Component("vevent");
		vevent.addPropertyWithValue("uid", ev.id);
		vevent.addPropertyWithValue("summary", ev.title);
		if (ev.description)
			vevent.addPropertyWithValue("description", ev.description);
		if (ev.location) vevent.addPropertyWithValue("location", ev.location);
		if (ev.url) vevent.addPropertyWithValue("url", ev.url);

		if (ev.allDay) {
			vevent.addPropertyWithValue(
				"dtstart",
				ICAL.Time.fromDateString(ev.start.split("T")[0]),
			);
			if (ev.end)
				vevent.addPropertyWithValue(
					"dtend",
					ICAL.Time.fromDateString(ev.end.split("T")[0]),
				);
		} else {
			vevent.addPropertyWithValue(
				"dtstart",
				ICAL.Time.fromJSDate(new Date(ev.start)),
			);
			if (ev.end) {
				vevent.addPropertyWithValue(
					"dtend",
					ICAL.Time.fromJSDate(new Date(ev.end)),
				);
			}
		}

		vevent.addPropertyWithValue(
			"dtstamp",
			ICAL.Time.fromJSDate(ev.createdAt ? new Date(ev.createdAt) : new Date()),
		);
		if (ev.lastModified) {
			vevent.addPropertyWithValue(
				"last-modified",
				ICAL.Time.fromJSDate(new Date(ev.lastModified)),
			);
		}

		if (ev.recurrenceRule) {
			vevent.addPropertyWithValue(
				"rrule",
				ICAL.Recur.fromString(ev.recurrenceRule),
			);
		}

		comp.addSubcomponent(vevent);
	});

	return comp.toString();
}
