// Sichtbare Hinweise auf Basis der §§ 3-5 ArbZG (Höchstarbeitszeit,
// Ruhepausen, Ruhezeit) — AUSDRÜCKLICH keine rechtssichere, automatisch
// durchgesetzte Compliance-Prüfung (keine harte Sperre, keine 6-Monats-
// Durchschnittsrechnung nach § 3 Satz 2, keine Berücksichtigung von
// Ausnahmetatbeständen). Eine KI/Software kann echte Rechtssicherheit nicht
// "herstellen" — das bleibt Sache von Anwalt/Steuerberater (siehe
// project_rakku_v2_personalsystem.md). Das hier ist ein technischer Beitrag
// Richtung Konformität: sichtbare Warnungen statt stillem Ignorieren.
//
// Regeln, vereinfacht auf Tagesbasis:
// - § 3: werktäglich max. 10 Std. (harte Obergrenze im Gesetz, 8 Std. ist der
//   Regelfall mit Ausgleichspflicht über 6 Monate/24 Wochen - diese
//   Ausgleichsrechnung wird hier NICHT nachgebildet, nur die 8h-Schwelle als
//   Hinweis und die 10h-Schwelle als deutlichere Warnung).
// - § 4: mehr als 6 Std. am Stück ohne mind. 30 Min. Pause, bzw. mehr als
//   9 Std. ohne mind. 45 Min. Pause insgesamt an dem Tag.
// - § 5: mind. 11 Std. ununterbrochene Ruhezeit zwischen zwei Arbeitstagen.

export type ComplianceWarning = {
  type: "max_hours_10" | "over_8h" | "missing_break_6h" | "missing_break_9h" | "missing_rest_11h";
  date: string; // YYYY-MM-DD, Bezugstag
  message: string;
};

type Entry = { clockIn: Date; clockOut: Date | null };

// Lokale (Server-Zeitzone Europe/Berlin) statt UTC-Tagesgrenze - mit
// toISOString() wäre z. B. 25.09. 00:30 Uhr Ortszeit (= 24.09. 22:30 UTC bei
// Sommerzeit) fälschlich dem 24.09. zugeordnet worden und hätte sich mit
// einer Schicht an dem Tag zu einer Falsch-Warnung summiert (beim Testen der
// Ruhezeit-Prüfung selbst aufgefallen, 24.09.2026).
function dayKey(d: Date): string {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
}

function formatHours(ms: number): string {
  return (ms / 3_600_000).toLocaleString("de-DE", { maximumFractionDigits: 1 });
}

// entries: alle Einträge EINES Mitarbeiters, beliebige Reihenfolge, roher
// Zeitraum - wird hier selbst sortiert/gruppiert. Ein offener Eintrag
// (clockOut null) zählt bis "jetzt".
export function computeComplianceWarnings(entries: Entry[]): ComplianceWarning[] {
  const now = new Date();
  const sorted = [...entries]
    .map((e) => ({ clockIn: new Date(e.clockIn), clockOut: e.clockOut ? new Date(e.clockOut) : now }))
    .sort((a, b) => a.clockIn.getTime() - b.clockIn.getTime());

  const warnings: ComplianceWarning[] = [];

  // Pro Kalendertag gruppieren (nach clockIn-Datum) für § 3/§ 4.
  const byDay = new Map<string, typeof sorted>();
  for (const e of sorted) {
    const key = dayKey(e.clockIn);
    if (!byDay.has(key)) byDay.set(key, []);
    byDay.get(key)!.push(e);
  }

  for (const [date, dayEntries] of byDay) {
    const totalMs = dayEntries.reduce((sum, e) => sum + (e.clockOut.getTime() - e.clockIn.getTime()), 0);
    const pauseMs = dayEntries.slice(1).reduce((sum, e, i) => sum + Math.max(0, e.clockIn.getTime() - dayEntries[i].clockOut.getTime()), 0);

    if (totalMs > 10 * 3_600_000) {
      warnings.push({ type: "max_hours_10", date, message: `Höchstarbeitszeit überschritten: ${formatHours(totalMs)} Std. an einem Tag (Obergrenze 10 Std., § 3 ArbZG).` });
    } else if (totalMs > 8 * 3_600_000) {
      warnings.push({ type: "over_8h", date, message: `${formatHours(totalMs)} Std. gearbeitet — über der regulären 8-Std.-Grenze (§ 3 ArbZG), muss über 6 Monate ausgeglichen werden.` });
    }

    // pauseMs kennt nur Pausen, die durch Aus-/Wiedereinstempeln erfasst
    // wurden - wer eine Mittagspause informell "off the clock" macht ohne
    // dafür auszustempeln, bekommt hier trotzdem eine Warnung, weil das
    // System davon nichts wissen kann. Erwartetes, nicht überraschendes
    // Verhalten bei einem einzelnen durchgehenden Ein-/Ausstempeln über
    // mehr als 6/9 Std. - kein Bug, aber erklärt, warum das ohne die
    // Gewohnheit "Pause = kurz ausstempeln" im Team recht oft aufleuchtet.
    if (totalMs > 9 * 3_600_000 && pauseMs < 45 * 60_000) {
      warnings.push({ type: "missing_break_9h", date, message: `Über 9 Std. gearbeitet, aber nur ${Math.round(pauseMs / 60_000)} Min. Pause erfasst (mind. 45 Min. nötig, § 4 ArbZG).` });
    } else if (totalMs > 6 * 3_600_000 && pauseMs < 30 * 60_000) {
      warnings.push({ type: "missing_break_6h", date, message: `Über 6 Std. gearbeitet, aber nur ${Math.round(pauseMs / 60_000)} Min. Pause erfasst (mind. 30 Min. nötig, § 4 ArbZG).` });
    }
  }

  // § 5 Ruhezeit: NUR der Übergang zwischen zwei Arbeitstagen zählt (letztes
  // Tagesende -> erster Beginn am nächsten Arbeitstag) - nicht jede Lücke
  // zwischen zwei Einträgen, sonst würde jede normale Mittagspause
  // fälschlich als Ruhezeit-Verstoß auftauchen (beim Testen aufgefallen,
  // 24.09.2026: ein 30-Min-Mittag löste sonst eine Warnung aus).
  const days = [...byDay.keys()].sort();
  for (let i = 1; i < days.length; i++) {
    const prevDayEntries = byDay.get(days[i - 1])!;
    const currDayEntries = byDay.get(days[i])!;
    const prevClockOut = prevDayEntries[prevDayEntries.length - 1].clockOut;
    const currClockIn = currDayEntries[0].clockIn;
    const gapMs = currClockIn.getTime() - prevClockOut.getTime();
    if (gapMs > 0 && gapMs < 11 * 3_600_000) {
      warnings.push({
        type: "missing_rest_11h",
        date: days[i],
        message: `Nur ${formatHours(gapMs)} Std. Ruhezeit vor dieser Schicht (mind. 11 Std. nötig, § 5 ArbZG).`,
      });
    }
  }

  return warnings.sort((a, b) => b.date.localeCompare(a.date));
}
