import { redirect } from "next/navigation";
import { isAdminSession, hasPermission, getAllPermissions } from "@/lib/adminAuth";
import { getSessionClientId } from "@/lib/auth";
import { connectDB } from "@/lib/db";
import { TimeEntry } from "@/models/TimeEntry";
import { Client } from "@/models/Client";
import { AdminNavLinks } from "@/components/admin/AdminNavLinks";
import { AdminPageHeader } from "@/components/admin/AdminPageHeader";
import { AdminEmptyState } from "@/components/admin/AdminEmptyState";
import { ClockInOutPanel } from "@/components/admin/ClockInOutPanel";
import { computeComplianceWarnings, type ComplianceWarning } from "@/lib/workingTimeCompliance";

export const dynamic = "force-dynamic";

function formatDuration(ms: number): string {
  const minutes = Math.floor(ms / 60_000);
  return `${Math.floor(minutes / 60)} Std. ${minutes % 60} Min.`;
}

function startOfDay(d: Date): Date {
  return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
// Montag als Wochenstart (DE-Konvention), unabhängig vom aktuellen Wochentag.
function startOfWeek(d: Date): Date {
  const day = d.getDay();
  const diff = (day + 6) % 7;
  return startOfDay(new Date(d.getTime() - diff * 86_400_000));
}

// Für abgeschlossene UND noch offene Einträge - ein offener Eintrag zählt bis
// "jetzt", nicht bis zu einem (nicht vorhandenen) clockOut.
function sumDuration(entries: { clockIn: Date; clockOut: Date | null }[], since: Date): number {
  const now = Date.now();
  return entries.reduce((sum, e) => {
    const start = Math.max(new Date(e.clockIn).getTime(), since.getTime());
    const end = e.clockOut ? new Date(e.clockOut).getTime() : now;
    return sum + Math.max(0, end - start);
  }, 0);
}

// Nicht Teil der ursprünglichen Alle-6-Aufgaben-Vorlage, sondern eigene
// Entscheidung im Rahmen des vom Nutzer explizit eingeräumten Spielraums
// ("Personalsystem ausführlicher/größer anlegen") - siehe Rückmeldung.
export default async function AdminZeiterfassungPage({ params }: { params: Promise<{ locale: string }> }) {
  if (!(await isAdminSession())) redirect("/de/login?next=%2Fde%2Fadmin%2Fzeiterfassung");
  const { locale } = await params;

  const [permissions, clientId, canViewAll] = await Promise.all([
    getAllPermissions(),
    getSessionClientId(),
    hasPermission("hr"),
  ]);
  if (!clientId) redirect(`/${locale}/login`);

  await connectDB();
  const now = new Date();
  const todayStart = startOfDay(now);
  const weekStart = startOfWeek(now);

  const complianceWindowStart = new Date(now.getTime() - 30 * 86_400_000);

  const [openEntry, weekEntries, recentEntries, ownComplianceEntries] = await Promise.all([
    TimeEntry.findOne({ clientId, clockOut: null }).lean(),
    // Ab Wochenstart reicht, um sowohl die Tages- als auch die Wochensumme
    // daraus zu berechnen - ein zweiter, engerer Query für "heute" wäre nur
    // eine Teilmenge derselben Daten.
    TimeEntry.find({ clientId, clockIn: { $gte: weekStart } }).sort({ clockIn: -1 }).lean(),
    TimeEntry.find({ clientId }).sort({ clockIn: -1 }).limit(10).lean(),
    TimeEntry.find({ clientId, clockIn: { $gte: complianceWindowStart } }).lean(),
  ]);

  const todayMs = sumDuration(weekEntries, todayStart);
  const weekMs = sumDuration(weekEntries, weekStart);
  const ownWarnings = computeComplianceWarnings(ownComplianceEntries);

  let currentlyClockedIn: { name: string; since: Date }[] = [];
  const teamWarnings: (ComplianceWarning & { staffName: string })[] = [];
  if (canViewAll) {
    const [openEntries, complianceEntries] = await Promise.all([
      TimeEntry.find({ clockOut: null }).sort({ clockIn: 1 }).lean(),
      TimeEntry.find({ clockIn: { $gte: complianceWindowStart } }).lean(),
    ]);
    const relevantIds = new Set([...openEntries, ...complianceEntries].map((e) => String(e.clientId)));
    const staffById = new Map(
      (await Client.find({ _id: { $in: [...relevantIds] } }).select("name").lean()).map((c) => [String(c._id), c.name])
    );
    currentlyClockedIn = openEntries.map((e) => ({ name: staffById.get(String(e.clientId)) || "—", since: new Date(e.clockIn) }));

    const entriesByStaff = new Map<string, typeof complianceEntries>();
    for (const e of complianceEntries) {
      const key = String(e.clientId);
      if (!entriesByStaff.has(key)) entriesByStaff.set(key, []);
      entriesByStaff.get(key)!.push(e);
    }
    for (const [staffId, entries] of entriesByStaff) {
      const name = staffById.get(staffId) || "—";
      for (const w of computeComplianceWarnings(entries)) teamWarnings.push({ ...w, staffName: name });
    }
    teamWarnings.sort((a, b) => b.date.localeCompare(a.date));
  }

  return (
    <main className="px-6 pt-4 pb-24 max-w-5xl mx-auto">
      <AdminNavLinks permissions={permissions} />
      <AdminPageHeader
        title="Zeiterfassung"
        subtitle="Ein-/Ausstempeln für die eigene Arbeitszeit. Zeitstempel-Basis mit Hinweisen zu Pausen/Höchstarbeitszeit/Ruhezeit nach ArbZG — keine rechtsverbindliche, vollautomatisch durchgesetzte Compliance-Prüfung (keine harte Sperre, keine 6-Monats-Ausgleichsrechnung)."
      />

      <ClockInOutPanel clockInSince={openEntry ? new Date(openEntry.clockIn).toISOString() : null} />

      {ownWarnings.length > 0 && (
        <div className="mt-4 flex flex-col gap-2">
          {ownWarnings.map((w, i) => (
            <div key={i} className="border border-amber-400/30 bg-amber-400/5 rounded-xl px-4 py-3 text-xs text-amber-400">
              <span className="font-medium">
                {new Date(w.date).toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" })}:
              </span>{" "}
              {w.message}
            </div>
          ))}
        </div>
      )}

      <div className="grid grid-cols-2 gap-3 mt-6 mb-8">
        <div className="bg-[var(--rk-surface)] border border-white/10 rounded-xl p-4">
          <p className="text-xs uppercase tracking-[0.1em] text-[var(--rk-ink-muted)] mb-1">Heute</p>
          <p className="text-lg text-[var(--rk-ink)]">{formatDuration(todayMs)}</p>
        </div>
        <div className="bg-[var(--rk-surface)] border border-white/10 rounded-xl p-4">
          <p className="text-xs uppercase tracking-[0.1em] text-[var(--rk-ink-muted)] mb-1">Diese Woche</p>
          <p className="text-lg text-[var(--rk-ink)]">{formatDuration(weekMs)}</p>
        </div>
      </div>

      {canViewAll && (
        <div className="mb-8">
          <h2 className="text-sm font-medium text-[var(--rk-ink)] mb-3">Aktuell eingestempelt</h2>
          {currentlyClockedIn.length === 0 ? (
            <AdminEmptyState message="Gerade niemand eingestempelt." />
          ) : (
            <div className="flex flex-col gap-2">
              {currentlyClockedIn.map((e, i) => (
                <div key={i} className="flex items-center justify-between bg-[var(--rk-surface)] border border-white/10 rounded-xl px-4 py-3 text-sm">
                  <span>{e.name}</span>
                  <span className="text-xs text-[var(--rk-ink-muted)]">
                    seit {e.since.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })}
                  </span>
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {canViewAll && teamWarnings.length > 0 && (
        <div className="mb-8">
          <h2 className="text-sm font-medium text-[var(--rk-ink)] mb-3">ArbZG-Hinweise im Team (letzte 30 Tage)</h2>
          <div className="flex flex-col gap-2">
            {teamWarnings.map((w, i) => (
              <div key={i} className="border border-amber-400/30 bg-amber-400/5 rounded-xl px-4 py-3 text-xs text-amber-400">
                <span className="font-medium">
                  {w.staffName} · {new Date(w.date).toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" })}:
                </span>{" "}
                {w.message}
              </div>
            ))}
          </div>
        </div>
      )}

      <div>
        <h2 className="text-sm font-medium text-[var(--rk-ink)] mb-3">Letzte Einträge</h2>
        {recentEntries.length === 0 ? (
          <AdminEmptyState message="Noch keine Einträge." />
        ) : (
          <div className="flex flex-col gap-2">
            {recentEntries.map((e) => {
              const clockIn = new Date(e.clockIn);
              const clockOut = e.clockOut ? new Date(e.clockOut) : null;
              return (
                <div key={String(e._id)} className="flex items-center justify-between bg-[var(--rk-surface)] border border-white/10 rounded-xl px-4 py-3 text-sm">
                  <span>{clockIn.toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric" })}</span>
                  <span className="text-[var(--rk-ink-muted)]">
                    {clockIn.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })} –{" "}
                    {clockOut ? clockOut.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }) : "läuft"}
                  </span>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </main>
  );
}
