/**
 * Zeitzonen-Hilfsfunktionen fuer Reporting.
 * SQLite speichert alle Zeitstempel als UTC (datetime('now')).
 * Das Admin-Dashboard soll Daten aber in einer festen Zielzeitzone
 * (Europe/Berlin) anzeigen, damit "Heute", Stunden und Tages-Buckets
 * fuer Menschen in Deutschland intuitiv sind.
 */

export const REPORTING_TZ = 'Europe/Berlin';

/**
 * Offset der Zielzeitzone relativ zu UTC fuer einen gegebenen UTC-Zeitpunkt.
 * Rueckgabe in Millisekunden: positiv, wenn die Zielzeitzone vor UTC liegt
 * (z.B. +2h im Sommer in Berlin), negativ fuer Zeitzonen hinter UTC.
 */
export function getTzOffsetMs(date: Date, tz: string): number {
  const utcString = date.toLocaleString('en-US', { timeZone: 'UTC' });
  const tzString = date.toLocaleString('en-US', { timeZone: tz });
  return new Date(utcString).getTime() - new Date(tzString).getTime();
}

/**
 * Ermittelt den UTC-Zeitstempel, an dem in der Zielzeitzone das angegebene
 * lokale Datum/Uhrzeit erreicht ist.
 * Beispiel: utcForTzLocal('2026-08-13', '00:00:00', 'Europe/Berlin')
 *          -> 2026-08-12 22:00:00 UTC (CEST, +2h)
 */
export function utcForTzLocal(isoDate: string, time: string, tz: string): Date {
  const anchorMs = Date.parse(`${isoDate}T${time}Z`);
  let utcMs = anchorMs;
  // 3 Iterationen reichen, da sich der Offset innerhalb weniger Stunden
  // hoechstens einmal aendert (Sommer-/Winterzeitumstellung).
  for (let i = 0; i < 3; i++) {
    utcMs = anchorMs + getTzOffsetMs(new Date(utcMs), tz);
  }
  return new Date(utcMs);
}

/**
 * Liefert Datumsteile (Jahr, Monat, Tag, Stunde, Minute, Sekunde) so, wie sie
 * in der Zielzeitzone zum gegebenen UTC-Zeitpunkt gelten.
 */
export function getDatePartsInTz(date: Date, tz: string) {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone: tz,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  }).formatToParts(date);
  const get = (type: string) => parts.find((p) => p.type === type)?.value ?? '00';
  return {
    year: get('year'),
    month: get('month'),
    day: get('day'),
    hour: get('hour'),
    minute: get('minute'),
    second: get('second'),
  };
}

/** ISO-Datum (YYYY-MM-DD) des UTC-Zeitpunkts in der Zielzeitzone. */
export function formatDateIsoInTz(date: Date, tz: string): string {
  const p = getDatePartsInTz(date, tz);
  return `${p.year}-${p.month}-${p.day}`;
}

/** Jahr-Monat (YYYY-MM) des UTC-Zeitpunkts in der Zielzeitzone. */
export function formatMonthIsoInTz(date: Date, tz: string): string {
  const p = getDatePartsInTz(date, tz);
  return `${p.year}-${p.month}`;
}

/** Stunde (0-23) des UTC-Zeitpunkts in der Zielzeitzone. */
export function getHourInTz(date: Date, tz: string): number {
  return parseInt(getDatePartsInTz(date, tz).hour, 10);
}

/** Start des Tages (00:00:00) in der Zielzeitzone, zurueckgegeben als UTC-Date. */
export function startOfDayInTz(date: Date, tz: string): Date {
  return utcForTzLocal(formatDateIsoInTz(date, tz), '00:00:00', tz);
}

/** Ende des Tages (23:59:59) in der Zielzeitzone, zurueckgegeben als UTC-Date. */
export function endOfDayInTz(date: Date, tz: string): Date {
  return utcForTzLocal(formatDateIsoInTz(date, tz), '23:59:59', tz);
}

/** Konvertiert ein UTC-Date in SQLite-kompaktes UTC-Format. */
export function toSqliteUtc(date: Date): string {
  return date.toISOString().replace('T', ' ').slice(0, 19);
}

/** Parst einen SQLite-UTC-String zurueck in ein UTC-Date. */
export function parseSqliteUtc(sqlite: string): Date {
  return new Date(sqlite.replace(' ', 'T') + 'Z');
}

/**
 * Formatiert ein ISO-Datum (YYYY-MM-DD) oder Jahr-Monat (YYYY-MM) fuer die
 * deutsche Anzeige in der Zielzeitzone. Wird im Frontend genutzt, um Labels
 * aus dem Backend (die bereits in der Zielzeitzone generiert wurden) sicher
 * als Berlin-Zeit anzuzeigen, ohne die Browser-Systemzeitzone zu verwenden.
 */
export function formatLabelInTz(iso: string, tz: string, options: Intl.DateTimeFormatOptions): string {
  // ISO-Datum bzw. Jahr-Monat als UTC-Mitternacht parsen, damit es in der
  // Zielzeitzone exakt den gewuenschten Tag repraesentiert.
  const date = new Date(`${iso}T00:00:00Z`);
  return new Intl.DateTimeFormat('de-DE', { timeZone: tz, ...options }).format(date);
}
