/**
 * `@platform-modules/util/timezone` — IANA time-zone validation + listing.
 *
 * Pure `Intl` (zero-dep, Workers-safe). For per-user / per-tenant zone selection in
 * global / multi-region apps: narrow an arbitrary string at the trust boundary, enumerate
 * the runtime's zones, group them for a picker. No host default is baked in — `UTC` is the
 * neutral listing fallback, never a policy choice (any host-specific default is intentionally
 * stripped — zone defaults are host policy, not module policy).
 */

/** A string proven to be a runtime-recognized IANA time zone (narrowed by `isValidTimezone`). */
export type IanaTimezone = string & { readonly __brand: 'IanaTimezone' }

/** The neutral zero-offset zone — the listing fallback, never a host's chosen default. */
export const UTC = 'UTC' as IanaTimezone

/**
 * Narrow an arbitrary string to `IanaTimezone`. Trust-boundary validator: a zone string
 * from a user / API is unsafe until this returns true. Empty → false; unknown zone → false.
 */
export function isValidTimezone(tz: string): tz is IanaTimezone {
  if (!tz) return false
  try {
    // Constructing with the zone throws RangeError on an unrecognized IANA name.
    new Intl.DateTimeFormat(undefined, { timeZone: tz })
    return true
  } catch {
    return false
  }
}

let cachedZones: readonly IanaTimezone[] | undefined

/**
 * All IANA zones the runtime supports, sorted ascending. Memoized + frozen — the set is
 * static per runtime, so the `Intl.supportedValuesOf` call + sort run once and the returned
 * snapshot is immutable (mutate a copy). Falls back to `[UTC]` where `supportedValuesOf` is absent.
 */
export function listSupportedTimezones(): readonly IanaTimezone[] {
  if (cachedZones) return cachedZones
  const intlWithSupported = Intl as unknown as {
    supportedValuesOf?: (key: string) => string[]
  }
  const zones = intlWithSupported.supportedValuesOf
    ? intlWithSupported.supportedValuesOf('timeZone')
    : [UTC]
  cachedZones = Object.freeze([...zones].sort() as IanaTimezone[])
  return cachedZones
}

/**
 * Group zones by IANA continent prefix (`Europe/Paris` → `Europe`); a zone with no `/`
 * (e.g. `UTC`) lands in `Other`. For rendering a grouped zone-picker.
 */
export function groupTimezonesByContinent(
  zones: readonly IanaTimezone[],
): Record<string, IanaTimezone[]> {
  const out: Record<string, IanaTimezone[]> = {}
  for (const zone of zones) {
    const continent = zone.includes('/') ? zone.slice(0, zone.indexOf('/')) : 'Other'
    ;(out[continent] ??= []).push(zone)
  }
  return out
}
