"use server";

import { revalidatePath } from "next/cache";
import { prisma } from "@/lib/prisma";
import { requireSession } from "@/lib/auth/session";
import { createNotification } from "@/lib/notifications";
import { getRunningEntry, type TimeEntryDTO } from "./queries";

async function guard(): Promise<string | null> {
  const session = await requireSession();
  return session.user.permissions?.includes("time.track") ? session.user.id : null;
}

async function validProjectId(userId: string, projectId: string | null | undefined): Promise<string | null> {
  if (!projectId) return null;
  const p = await prisma.project.findUnique({ where: { id: projectId }, select: { id: true } });
  return p?.id ?? null;
}

export type TimeResult = { entry?: TimeEntryDTO; error?: string };

/** Startet einen Timer (nur einer gleichzeitig). */
export async function startTimerAction(projectId?: string | null, note?: string): Promise<TimeResult> {
  const userId = await guard();
  if (!userId) return { error: "Keine Berechtigung." };

  const running = await getRunningEntry(userId);
  if (running) return { error: "Es läuft bereits ein Timer." };

  await prisma.timeEntry.create({
    data: {
      userId,
      projectId: await validProjectId(userId, projectId),
      startedAt: new Date(),
      note: note?.trim().slice(0, 500) || null,
      source: "TIMER",
      status: "RUNNING",
    },
  });
  revalidatePath("/time");
  return {};
}

/** Stoppt den laufenden Timer und berechnet die Dauer. */
export async function stopTimerAction(): Promise<TimeResult> {
  const userId = await guard();
  if (!userId) return { error: "Keine Berechtigung." };

  const running = await prisma.timeEntry.findFirst({
    where: { userId, status: "RUNNING" },
    select: { id: true, startedAt: true },
  });
  if (!running) return { error: "Kein laufender Timer." };

  const now = new Date();
  const seconds = Math.max(0, Math.round((now.getTime() - running.startedAt.getTime()) / 1000));
  await prisma.timeEntry.update({
    where: { id: running.id },
    data: { endedAt: now, durationSeconds: seconds, status: "OPEN" },
  });
  revalidatePath("/time");
  return {};
}

/** Manuellen Eintrag mit Datum + Start/Ende hinzufügen. */
export async function addManualEntryAction(input: {
  date: string;
  start: string;
  end: string;
  projectId?: string | null;
  note?: string;
}): Promise<TimeResult> {
  const userId = await guard();
  if (!userId) return { error: "Keine Berechtigung." };

  const startedAt = new Date(`${input.date}T${input.start}`);
  const endedAt = new Date(`${input.date}T${input.end}`);
  if (Number.isNaN(startedAt.getTime()) || Number.isNaN(endedAt.getTime())) {
    return { error: "Ungültige Zeitangabe." };
  }
  if (endedAt <= startedAt) return { error: "Ende muss nach dem Start liegen." };

  const seconds = Math.round((endedAt.getTime() - startedAt.getTime()) / 1000);
  // Manuelle Einträge müssen von der zuständigen Person freigegeben werden.
  await prisma.timeEntry.create({
    data: {
      userId,
      projectId: await validProjectId(userId, input.projectId),
      startedAt,
      endedAt,
      durationSeconds: seconds,
      note: input.note?.trim().slice(0, 500) || null,
      source: "MANUAL",
      status: "SUBMITTED",
    },
  });

  // Zuständige Person benachrichtigen.
  const me = await prisma.user.findUnique({ where: { id: userId }, select: { supervisorId: true, name: true } });
  if (me?.supervisorId) {
    await createNotification({
      userId: me.supervisorId,
      type: "TIME",
      title: "Arbeitszeit zur Freigabe",
      body: `${me.name} hat einen manuellen Eintrag eingereicht.`,
      link: "/admin/users",
    });
  }

  revalidatePath("/time");
  revalidatePath("/admin/users");
  return {};
}

/** Freigabe/Ablehnung eines eingereichten Eintrags (Vorgesetzte(r) oder time.approve). */
export async function decideTimeEntryAction(entryId: string, approve: boolean): Promise<TimeResult> {
  const session = await requireSession();
  const entry = await prisma.timeEntry.findUnique({
    where: { id: entryId },
    select: { status: true, userId: true, user: { select: { supervisorId: true } } },
  });
  if (!entry) return { error: "Nicht gefunden." };
  if (entry.status !== "SUBMITTED") return { error: "Eintrag ist nicht offen." };

  const isSupervisor = entry.user.supervisorId === session.user.id;
  const canApprove = Boolean(session.user.permissions?.includes("time.approve"));
  if (!isSupervisor && !canApprove) return { error: "Keine Berechtigung." };

  await prisma.timeEntry.update({
    where: { id: entryId },
    data: { status: approve ? "APPROVED" : "REJECTED", approvedById: session.user.id, decidedAt: new Date() },
  });
  await createNotification({
    userId: entry.userId,
    type: "TIME",
    title: approve ? "Arbeitszeit freigegeben" : "Arbeitszeit abgelehnt",
    body: approve ? "Dein manueller Eintrag wurde freigegeben." : "Dein manueller Eintrag wurde abgelehnt.",
    link: "/time",
  });
  revalidatePath("/admin/users");
  revalidatePath("/time");
  return {};
}

export async function updateEntryNoteAction(entryId: string, note: string): Promise<TimeResult> {
  const userId = await guard();
  if (!userId) return { error: "Keine Berechtigung." };
  await prisma.timeEntry.updateMany({
    where: { id: entryId, userId },
    data: { note: note.trim().slice(0, 500) || null },
  });
  revalidatePath("/time");
  return {};
}

export async function deleteEntryAction(entryId: string): Promise<TimeResult> {
  const userId = await guard();
  if (!userId) return { error: "Keine Berechtigung." };
  await prisma.timeEntry.deleteMany({ where: { id: entryId, userId, status: { not: "APPROVED" } } });
  revalidatePath("/time");
  return {};
}
