"use server";

import { revalidatePath } from "next/cache";
import { prisma } from "@/lib/prisma";
import { requireSession } from "@/lib/auth/session";
import { createNotifications } from "@/lib/notifications";
import type { MeetingResponse } from "@prisma/client";

export type MeetingResult = { id?: string; error?: string };

function parseDT(v: string | null | undefined): Date | null {
  if (!v) return null;
  const d = new Date(v);
  return Number.isNaN(d.getTime()) ? null : d;
}

async function validUserIds(ids: string[] | undefined): Promise<string[]> {
  if (!ids?.length) return [];
  const rows = await prisma.user.findMany({ where: { id: { in: ids } }, select: { id: true } });
  return rows.map((r) => r.id);
}

export async function createMeetingAction(input: {
  title: string;
  description?: string;
  startAt: string;
  endAt: string;
  location?: string;
  participantIds: string[];
}): Promise<MeetingResult> {
  const session = await requireSession();
  if (!session.user.permissions?.includes("meetings.create") && !session.user.permissions?.includes("meetings.manage")) {
    return { error: "Keine Berechtigung." };
  }

  const title = input.title.trim();
  if (!title) return { error: "Titel erforderlich." };
  const startAt = parseDT(input.startAt);
  const endAt = parseDT(input.endAt);
  if (!startAt || !endAt) return { error: "Bitte Start und Ende angeben." };
  if (endAt <= startAt) return { error: "Ende muss nach dem Start liegen." };

  const participants = await validUserIds(input.participantIds);
  const memberSet = new Set([...participants, session.user.id]);

  const meeting = await prisma.meeting.create({
    data: {
      title: title.slice(0, 200),
      description: input.description?.trim() || null,
      startAt,
      endAt,
      location: input.location?.trim().slice(0, 200) || null,
      // Ersteller sagt automatisch zu; alle anderen zunächst offen.
      createdById: session.user.id,
      participants: {
        create: [...memberSet].map((userId) => ({
          userId,
          response: userId === session.user.id ? "ACCEPTED" : "PENDING",
        })),
      },
    },
    select: { id: true },
  });

  const notify = [...memberSet].filter((id) => id !== session.user.id);
  if (notify.length) {
    await createNotifications(notify, {
      type: "MEETING",
      title: "Neues Meeting",
      body: `${title} — ${startAt.toLocaleString("de-DE", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" })}`,
      link: "/meetings",
    });
  }

  revalidatePath("/meetings");
  revalidatePath("/calendar");
  return { id: meeting.id };
}

/** Meeting verlegen/bearbeiten — nur Ersteller oder meetings.manage. */
export async function updateMeetingAction(
  meetingId: string,
  input: {
    title: string;
    description?: string;
    startAt: string;
    endAt: string;
    location?: string;
    participantIds: string[];
  },
): Promise<MeetingResult> {
  const session = await requireSession();
  const meeting = await prisma.meeting.findUnique({ where: { id: meetingId }, select: { createdById: true } });
  if (!meeting) return { error: "Nicht gefunden." };
  const canManage = Boolean(session.user.permissions?.includes("meetings.manage"));
  if (meeting.createdById !== session.user.id && !canManage) return { error: "Keine Berechtigung." };

  const title = input.title.trim();
  if (!title) return { error: "Titel erforderlich." };
  const startAt = parseDT(input.startAt);
  const endAt = parseDT(input.endAt);
  if (!startAt || !endAt) return { error: "Bitte Start und Ende angeben." };
  if (endAt <= startAt) return { error: "Ende muss nach dem Start liegen." };

  const participants = await validUserIds(input.participantIds);
  const memberSet = new Set([...participants, meeting.createdById]);
  const existing = await prisma.meetingParticipant.findMany({ where: { meetingId }, select: { userId: true } });
  const have = new Set(existing.map((e) => e.userId));
  const toAdd = [...memberSet].filter((id) => !have.has(id));
  const toRemove = [...have].filter((id) => !memberSet.has(id));

  await prisma.$transaction([
    prisma.meeting.update({
      where: { id: meetingId },
      data: {
        title: title.slice(0, 200),
        description: input.description?.trim() || null,
        startAt,
        endAt,
        location: input.location?.trim().slice(0, 200) || null,
      },
    }),
    ...toAdd.map((userId) =>
      prisma.meetingParticipant.create({
        data: { meetingId, userId, response: userId === meeting.createdById ? "ACCEPTED" : "PENDING" },
      }),
    ),
    ...(toRemove.length ? [prisma.meetingParticipant.deleteMany({ where: { meetingId, userId: { in: toRemove } } })] : []),
  ]);

  const notify = [...memberSet].filter((id) => id !== session.user.id);
  if (notify.length) {
    await createNotifications(notify, {
      type: "MEETING",
      title: "Meeting aktualisiert",
      body: `${title} — ${startAt.toLocaleString("de-DE", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" })}`,
      link: "/meetings",
    });
  }

  revalidatePath("/meetings");
  revalidatePath("/calendar");
  return { id: meetingId };
}

export async function respondMeetingAction(meetingId: string, response: MeetingResponse): Promise<MeetingResult> {
  const session = await requireSession();
  await prisma.meetingParticipant.updateMany({
    where: { meetingId, userId: session.user.id },
    data: { response },
  });
  revalidatePath("/meetings");
  return { id: meetingId };
}

export async function deleteMeetingAction(meetingId: string): Promise<MeetingResult> {
  const session = await requireSession();
  const meeting = await prisma.meeting.findUnique({ where: { id: meetingId }, select: { createdById: true } });
  if (!meeting) return { error: "Nicht gefunden." };
  const canManage = Boolean(session.user.permissions?.includes("meetings.manage"));
  if (meeting.createdById !== session.user.id && !canManage) return { error: "Keine Berechtigung." };
  await prisma.meeting.delete({ where: { id: meetingId } });
  revalidatePath("/meetings");
  revalidatePath("/calendar");
  return { id: meetingId };
}
