export interface TimezoneOption {
  zone: string;
  region: string;
  offsetMinutes: number;
  label: string;
}

function getOffsetMinutes(zone: string, at: Date = new Date()): number {
  try {
    const parts = new Intl.DateTimeFormat('en-US', {
      timeZone: zone,
      timeZoneName: 'longOffset',
    }).formatToParts(at);
    const tzPart = parts.find(p => p.type === 'timeZoneName')?.value ?? '';
    const m = tzPart.match(/GMT([+-])(\d{1,2}):?(\d{2})?/);
    if (!m) return 0;
    const sign = m[1] === '-' ? -1 : 1;
    const h = parseInt(m[2], 10);
    const mm = m[3] ? parseInt(m[3], 10) : 0;
    return sign * (h * 60 + mm);
  } catch {
    return 0;
  }
}

function formatOffset(mins: number): string {
  const sign = mins < 0 ? '-' : '+';
  const abs = Math.abs(mins);
  const h = String(Math.floor(abs / 60)).padStart(2, '0');
  const m = String(abs % 60).padStart(2, '0');
  return `UTC${sign}${h}:${m}`;
}

let cached: TimezoneOption[] | null = null;

export function getAllTimezones(): TimezoneOption[] {
  if (cached) return cached;
  // Intl.supportedValuesOf is available in Node 18+ and all evergreen browsers.
  // Fall back to a small static list if it isn't (e.g. very old runtimes).
  let zones: string[] = [];
  try {
    const intlAny = Intl as unknown as { supportedValuesOf?: (k: string) => string[] };
    zones = intlAny.supportedValuesOf?.('timeZone') ?? [];
  } catch {
    zones = [];
  }
  if (zones.length === 0) {
    zones = ['UTC', 'America/Los_Angeles', 'America/Denver', 'America/Chicago', 'America/New_York', 'Europe/London', 'Europe/Berlin', 'Asia/Kolkata', 'Asia/Shanghai', 'Asia/Tokyo', 'Australia/Sydney'];
  }
  const opts: TimezoneOption[] = zones
    .filter(zone => zone !== 'UTC')
    .map(zone => {
      const region = zone.includes('/') ? zone.split('/')[0] : 'Other';
      const offsetMinutes = getOffsetMinutes(zone);
      return { zone, region, offsetMinutes, label: `${zone.replace(/_/g, ' ')} (${formatOffset(offsetMinutes)})` };
    });
  // Sort: by region alphabetically, then by offset, then by zone name.
  opts.sort((a, b) => {
    if (a.region !== b.region) return a.region.localeCompare(b.region);
    if (a.offsetMinutes !== b.offsetMinutes) return a.offsetMinutes - b.offsetMinutes;
    return a.zone.localeCompare(b.zone);
  });
  // Prepend UTC explicitly — Intl.supportedValuesOf does not include 'UTC'.
  const utcEntry: TimezoneOption = { zone: 'UTC', region: 'UTC', offsetMinutes: 0, label: 'UTC (UTC+00:00)' };
  cached = [utcEntry, ...opts];
  return cached;
}

export function getBrowserTimezone(): string {
  try {
    return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
  } catch {
    return 'UTC';
  }
}
