/**
 * iCal Calendar Generation Utilities
 * Generate .ics files for events and calendar feeds
 */

export interface ICalEvent {
	id: string;
	title: string;
	description?: string;
	start_datetime: string;
	end_datetime: string;
	location?: string | null;
	location_url?: string | null;
	timezone?: string;
	status?: 'published' | 'cancelled' | 'draft';
	event_type_name?: string | null;
	organizer_name?: string;
	organizer_email?: string;
	url?: string;
	all_day?: boolean;
}

/**
 * Escape special characters for iCal format
 */
function escapeICalText(text: string): string {
	return text
		.replace(/\\/g, '\\\\')
		.replace(/;/g, '\\;')
		.replace(/,/g, '\\,')
		.replace(/\n/g, '\\n')
		.replace(/\r/g, '');
}

/**
 * Format a date for iCal (YYYYMMDDTHHMMSSZ format for UTC)
 */
function formatICalDate(dateStr: string, timezone?: string): string {
	const date = new Date(dateStr);
	// Format as UTC
	const year = date.getUTCFullYear();
	const month = String(date.getUTCMonth() + 1).padStart(2, '0');
	const day = String(date.getUTCDate()).padStart(2, '0');
	const hours = String(date.getUTCHours()).padStart(2, '0');
	const minutes = String(date.getUTCMinutes()).padStart(2, '0');
	const seconds = String(date.getUTCSeconds()).padStart(2, '0');
	return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
}

/**
 * Format a date for all-day events (YYYYMMDD format)
 */
function formatICalDateOnly(dateStr: string): string {
	const date = new Date(dateStr);
	const year = date.getFullYear();
	const month = String(date.getMonth() + 1).padStart(2, '0');
	const day = String(date.getDate()).padStart(2, '0');
	return `${year}${month}${day}`;
}

/**
 * Map event status to iCal status
 */
function getICalStatus(status?: string): string {
	switch (status) {
		case 'cancelled':
			return 'CANCELLED';
		case 'draft':
			return 'TENTATIVE';
		default:
			return 'CONFIRMED';
	}
}

/**
 * Fold long lines according to iCal spec (max 75 chars per line)
 */
function foldLine(line: string): string {
	const maxLength = 75;
	if (line.length <= maxLength) {
		return line;
	}

	const result: string[] = [];
	let remaining = line;

	// First line can be full length
	result.push(remaining.substring(0, maxLength));
	remaining = remaining.substring(maxLength);

	// Continuation lines start with a space and have maxLength-1 content
	while (remaining.length > 0) {
		result.push(' ' + remaining.substring(0, maxLength - 1));
		remaining = remaining.substring(maxLength - 1);
	}

	return result.join('\r\n');
}

/**
 * Generate a single iCal event entry
 */
export function generateICalEvent(event: ICalEvent, baseUrl: string = 'https://monacousa.org'): string {
	const uid = `${event.id}@monacousa.org`;
	const dtstamp = formatICalDate(new Date().toISOString());
	const created = dtstamp;
	const lastModified = dtstamp;

	const lines: string[] = [
		'BEGIN:VEVENT',
		`UID:${uid}`,
		`DTSTAMP:${dtstamp}`,
		`CREATED:${created}`,
		`LAST-MODIFIED:${lastModified}`
	];

	// Date/time
	if (event.all_day) {
		lines.push(`DTSTART;VALUE=DATE:${formatICalDateOnly(event.start_datetime)}`);
		// For all-day events, end date is exclusive, so add one day
		const endDate = new Date(event.end_datetime);
		endDate.setDate(endDate.getDate() + 1);
		lines.push(`DTEND;VALUE=DATE:${formatICalDateOnly(endDate.toISOString())}`);
	} else {
		lines.push(`DTSTART:${formatICalDate(event.start_datetime, event.timezone)}`);
		lines.push(`DTEND:${formatICalDate(event.end_datetime, event.timezone)}`);
	}

	// Summary (title)
	lines.push(foldLine(`SUMMARY:${escapeICalText(event.title)}`));

	// Description
	if (event.description) {
		lines.push(foldLine(`DESCRIPTION:${escapeICalText(event.description)}`));
	}

	// Location
	if (event.location) {
		lines.push(foldLine(`LOCATION:${escapeICalText(event.location)}`));
	}

	// URL
	const eventUrl = event.url || `${baseUrl}/events/${event.id}`;
	lines.push(`URL:${eventUrl}`);

	// Status
	lines.push(`STATUS:${getICalStatus(event.status)}`);

	// Categories
	if (event.event_type_name) {
		lines.push(`CATEGORIES:${escapeICalText(event.event_type_name)}`);
	}

	// Organizer
	if (event.organizer_email) {
		const organizerName = event.organizer_name || 'Monaco USA';
		lines.push(`ORGANIZER;CN=${escapeICalText(organizerName)}:mailto:${event.organizer_email}`);
	}

	// Sequence (for updates)
	lines.push('SEQUENCE:0');

	lines.push('END:VEVENT');

	return lines.join('\r\n');
}

/**
 * Generate a complete iCal calendar file for a single event
 */
export function generateSingleEventIcal(event: ICalEvent, baseUrl: string = 'https://monacousa.org'): string {
	const lines = [
		'BEGIN:VCALENDAR',
		'VERSION:2.0',
		'PRODID:-//Monaco USA//Event Calendar//EN',
		'CALSCALE:GREGORIAN',
		'METHOD:PUBLISH',
		`X-WR-CALNAME:${escapeICalText(event.title)}`,
		'X-WR-TIMEZONE:Europe/Monaco',
		generateICalEvent(event, baseUrl),
		'END:VCALENDAR'
	];

	return lines.join('\r\n') + '\r\n';
}

/**
 * Generate a complete iCal calendar feed for multiple events
 */
export function generateCalendarFeed(
	events: ICalEvent[],
	calendarName: string = 'Monaco USA Events',
	baseUrl: string = 'https://monacousa.org'
): string {
	const lines = [
		'BEGIN:VCALENDAR',
		'VERSION:2.0',
		'PRODID:-//Monaco USA//Event Calendar//EN',
		'CALSCALE:GREGORIAN',
		'METHOD:PUBLISH',
		`X-WR-CALNAME:${escapeICalText(calendarName)}`,
		'X-WR-TIMEZONE:Europe/Monaco',
		// Refresh interval hint (1 hour)
		'REFRESH-INTERVAL;VALUE=DURATION:PT1H',
		'X-PUBLISHED-TTL:PT1H'
	];

	// Add each event
	for (const event of events) {
		lines.push(generateICalEvent(event, baseUrl));
	}

	lines.push('END:VCALENDAR');

	return lines.join('\r\n') + '\r\n';
}

/**
 * Generate a Google Calendar URL for an event
 */
export function generateGoogleCalendarUrl(event: ICalEvent, baseUrl: string = 'https://monacousa.org'): string {
	const start = new Date(event.start_datetime);
	const end = new Date(event.end_datetime);

	// Format: YYYYMMDDTHHMMSSZ
	const formatGoogleDate = (date: Date) => {
		return date.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
	};

	const params = new URLSearchParams({
		action: 'TEMPLATE',
		text: event.title,
		dates: `${formatGoogleDate(start)}/${formatGoogleDate(end)}`,
		details: event.description || '',
		location: event.location || '',
		sprop: `website:${baseUrl}`,
		sf: 'true',
		output: 'xml'
	});

	return `https://www.google.com/calendar/render?${params.toString()}`;
}

/**
 * Generate an Outlook.com calendar URL for an event
 */
export function generateOutlookCalendarUrl(event: ICalEvent, baseUrl: string = 'https://monacousa.org'): string {
	const start = new Date(event.start_datetime);
	const end = new Date(event.end_datetime);

	// Outlook uses ISO format with URL encoding
	const params = new URLSearchParams({
		rru: 'addevent',
		startdt: start.toISOString(),
		enddt: end.toISOString(),
		subject: event.title,
		body: event.description || '',
		location: event.location || '',
		path: '/calendar/action/compose'
	});

	return `https://outlook.live.com/calendar/0/deeplink/compose?${params.toString()}`;
}

/**
 * Generate a Yahoo Calendar URL for an event
 */
export function generateYahooCalendarUrl(event: ICalEvent): string {
	const start = new Date(event.start_datetime);
	const end = new Date(event.end_datetime);

	// Duration in hours and minutes
	const durationMs = end.getTime() - start.getTime();
	const hours = Math.floor(durationMs / (1000 * 60 * 60));
	const minutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60));
	const duration = `${String(hours).padStart(2, '0')}${String(minutes).padStart(2, '0')}`;

	// Format: YYYYMMDDTHHMMSS
	const formatYahooDate = (date: Date) => {
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, '0');
		const day = String(date.getDate()).padStart(2, '0');
		const h = String(date.getHours()).padStart(2, '0');
		const m = String(date.getMinutes()).padStart(2, '0');
		const s = String(date.getSeconds()).padStart(2, '0');
		return `${year}${month}${day}T${h}${m}${s}`;
	};

	const params = new URLSearchParams({
		v: '60',
		title: event.title,
		st: formatYahooDate(start),
		dur: duration,
		desc: event.description || '',
		in_loc: event.location || ''
	});

	return `https://calendar.yahoo.com/?${params.toString()}`;
}
