import { isSameDay as isSameDayDateFns } from 'date-fns';
import { formatInTimeZone, toZonedTime } from 'date-fns-tz';
import { de, enGB, es, fr, it } from 'date-fns/locale';

import * as m from '$lib/paraglide/messages';
import { getLocale } from '$lib/paraglide/runtime';

import type { Locale as DateFnsLocale } from 'date-fns';

// Weekday and month names come from date-fns, so they have to follow the same
// locale the messages do.
const DATE_LOCALES: Record<string, DateFnsLocale> = { en: enGB, de, es, fr, it };

/**
 * Formats a UTC Date into a string for a specific timezone using date-fns patterns.
 * Patterns: 'HH:mm' for 24h time, 'EEE' for short weekday, etc.
 */
export function formatZoned(date: Date, timeZone: string, pattern: string): string {
	return formatInTimeZone(date, timeZone, pattern, {
		locale: DATE_LOCALES[getLocale()] ?? enGB
	});
}

/**
 * Checks if two dates are the same day in a specific timezone.
 * Important for comparing weather forecast days against a selected date.
 */
export function isSameDayInZone(date1: Date, date2: Date, timeZone: string): boolean {
	const z1 = toZonedTime(date1, timeZone);
	const z2 = toZonedTime(date2, timeZone);
	return isSameDayDateFns(z1, z2);
}

/**
 * Gets the numeric hour (0-23) for a date in a specific timezone.
 */
export function getZonedHour(date: Date, timeZone: string): number {
	return parseInt(formatInTimeZone(date, timeZone, 'H'), 10);
}

/**
 * Returns a relative label like "Today", "Tomorrow", "Yesterday",
 * or a formatted date string, all relative to the target timezone.
 */
export function getRelativeDayLabel(date: Date, timeZone: string): string {
	const now = new Date();
	const zonedDate = toZonedTime(date, timeZone);
	const zonedNow = toZonedTime(now, timeZone);

	if (isSameDayDateFns(zonedDate, zonedNow)) return m.day_today();

	const tomorrow = new Date(zonedNow);
	tomorrow.setDate(tomorrow.getDate() + 1);
	if (isSameDayDateFns(zonedDate, tomorrow)) return m.day_tomorrow();

	const yesterday = new Date(zonedNow);
	yesterday.setDate(yesterday.getDate() - 1);
	if (isSameDayDateFns(zonedDate, yesterday)) return m.day_yesterday();

	return formatZoned(date, timeZone, 'EEE d MMM');
}

/**
 * Formats a UTC offset in seconds to a string like "UTC+1" or "UTC-05:00"
 */
export function formatUtcOffset(offsetSeconds: number): string {
	const sign = offsetSeconds >= 0 ? '+' : '-';
	const abs = Math.abs(offsetSeconds);
	const hours = Math.floor(abs / 3600);
	const minutes = Math.floor((abs % 3600) / 60);
	const pad = (n: number) => n.toString().padStart(2, '0');
	return minutes === 0 ? `UTC${sign}${hours}` : `UTC${sign}${hours}:${pad(minutes)}`;
}
