"use server";

import { rm } from "node:fs/promises";
import { revalidatePath } from "next/cache";
import { prisma } from "@/lib/prisma";
import { requireSession } from "@/lib/auth/session";
import { getCloudScope, canWriteFolder, canWriteFile } from "./access";
import { cloudPath, isSafeCloudName } from "./storage";
import { cleanFileName } from "./format";

// ──────────────────────────────────────────────────────────────────────────
// Schreibzugriffe des Cloud-Speichers.
// ──────────────────────────────────────────────────────────────────────────

export type CloudResult = { ok?: true; id?: string; error?: string };

/** Nur Symbolnamen aus der bekannten Auswahl zulassen. */
function safeIcon(v: string | null | undefined): string | null {
  if (!v) return null;
  return /^[a-z-]{1,40}$/.test(v) ? v : null;
}

function safeColor(v: string | null | undefined): string | null {
  if (!v) return null;
  return /^#[0-9a-fA-F]{3,8}$/.test(v) ? v.slice(0, 16) : null;
}

async function guard() {
  const session = await requireSession();
  if (!session.user.permissions?.includes("cloud.manage")) {
    return { error: "Keine Berechtigung, Dateien zu verwalten." as const };
  }
  return { userId: session.user.id, scope: await getCloudScope(session.user.id) };
}

// ── Ordner ────────────────────────────────────────────────────────────────

export async function createFolderAction(
  name: string,
  parentId: string | null,
  color?: string | null,
  icon?: string | null,
): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  const clean = name.trim().slice(0, 160);
  if (!clean) return { error: "Name darf nicht leer sein." };
  if (!canWriteFolder(ctx.scope, parentId)) {
    return { error: "In diesem Ordner darfst du nichts anlegen." };
  }

  const folder = await prisma.cloudFolder.create({
    data: {
      name: clean,
      parentId,
      color: safeColor(color),
      icon: safeIcon(icon),
      ownerId: ctx.userId,
    },
    select: { id: true },
  });

  revalidatePath("/cloud");
  return { ok: true, id: folder.id };
}

export async function renameFolderAction(
  folderId: string,
  name: string,
  color?: string | null,
  icon?: string | null,
): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };
  if (!canWriteFolder(ctx.scope, folderId)) return { error: "Kein Änderungsrecht." };

  const existing = await prisma.cloudFolder.findUnique({
    where: { id: folderId },
    select: { teamId: true },
  });
  if (existing?.teamId) {
    return { error: "Team-Ordner werden automatisch verwaltet und folgen dem Team." };
  }

  const clean = name.trim().slice(0, 160);
  if (!clean) return { error: "Name darf nicht leer sein." };

  await prisma.cloudFolder.update({
    where: { id: folderId },
    data: { name: clean, color: safeColor(color), icon: safeIcon(icon) },
  });

  revalidatePath("/cloud");
  return { ok: true, id: folderId };
}

export async function deleteFolderAction(folderId: string): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  const folder = await prisma.cloudFolder.findUnique({
    where: { id: folderId },
    select: { ownerId: true, teamId: true },
  });
  if (!folder) return { error: "Ordner nicht gefunden." };
  if (folder.teamId) {
    return { error: "Team-Ordner können nicht gelöscht werden — sie gehören zum Team." };
  }
  if (folder.ownerId !== ctx.userId) {
    return { error: "Nur die Besitzer:in darf den Ordner löschen." };
  }

  // Alle betroffenen Dateien einsammeln, bevor die Datenbank aufräumt.
  const ids = new Set<string>([folderId]);
  for (let depth = 0; depth < 24; depth++) {
    const children = await prisma.cloudFolder.findMany({
      where: { parentId: { in: [...ids] } },
      select: { id: true },
    });
    const fresh = children.filter((c) => !ids.has(c.id));
    if (fresh.length === 0) break;
    for (const c of fresh) ids.add(c.id);
  }
  const files = await prisma.cloudFile.findMany({
    where: { folderId: { in: [...ids] } },
    select: { storedName: true },
  });

  await prisma.cloudFolder.delete({ where: { id: folderId } });

  for (const f of files) {
    if (isSafeCloudName(f.storedName)) {
      await rm(cloudPath(f.storedName), { force: true }).catch(() => {});
    }
  }

  revalidatePath("/cloud");
  return { ok: true };
}

// ── Dateien ───────────────────────────────────────────────────────────────

async function loadFile(fileId: string) {
  return prisma.cloudFile.findUnique({
    where: { id: fileId },
    select: { id: true, folderId: true, ownerId: true, storedName: true },
  });
}

export async function renameFileAction(fileId: string, name: string): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  const file = await loadFile(fileId);
  if (!file) return { error: "Datei nicht gefunden." };
  if (!canWriteFile(ctx.scope, file)) return { error: "Kein Änderungsrecht." };

  const clean = cleanFileName(name);
  if (!clean) return { error: "Name darf nicht leer sein." };

  await prisma.cloudFile.update({ where: { id: fileId }, data: { name: clean } });

  revalidatePath("/cloud");
  return { ok: true, id: fileId };
}

export async function moveFileAction(
  fileId: string,
  targetFolderId: string | null,
): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  const file = await loadFile(fileId);
  if (!file) return { error: "Datei nicht gefunden." };
  if (!canWriteFile(ctx.scope, file)) return { error: "Kein Änderungsrecht." };
  if (!canWriteFolder(ctx.scope, targetFolderId)) {
    return { error: "In den Zielordner darfst du nichts legen." };
  }

  await prisma.cloudFile.update({ where: { id: fileId }, data: { folderId: targetFolderId } });

  revalidatePath("/cloud");
  return { ok: true, id: fileId };
}

export async function deleteFileAction(fileId: string): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  const file = await loadFile(fileId);
  if (!file) return { error: "Datei nicht gefunden." };
  if (!canWriteFile(ctx.scope, file)) return { error: "Kein Löschrecht." };

  await prisma.cloudFile.delete({ where: { id: fileId } });
  if (isSafeCloudName(file.storedName)) {
    await rm(cloudPath(file.storedName), { force: true }).catch(() => {});
  }

  revalidatePath("/cloud");
  return { ok: true };
}

// ── Freigaben ─────────────────────────────────────────────────────────────

export type CloudShareInput = {
  userIds: string[];
  teamIds: string[];
  roleIds: string[];
  canEdit: boolean;
};

/** Freigaben eines Ordners oder einer Datei komplett neu setzen. */
export async function setCloudSharesAction(
  target: { folderId?: string; fileId?: string },
  input: CloudShareInput,
): Promise<CloudResult> {
  const ctx = await guard();
  if ("error" in ctx) return { error: ctx.error };

  let ownerId: string | null = null;
  if (target.folderId) {
    const folder = await prisma.cloudFolder.findUnique({
      where: { id: target.folderId },
      select: { ownerId: true, teamId: true },
    });
    if (folder?.teamId) {
      return { error: "Team-Ordner sind automatisch für alle Teammitglieder freigegeben." };
    }
    ownerId = folder?.ownerId ?? null;
  } else if (target.fileId) {
    const file = await loadFile(target.fileId);
    ownerId = file?.ownerId ?? null;
  }
  if (!ownerId) return { error: "Nicht gefunden." };
  if (ownerId !== ctx.userId) {
    return { error: "Nur die Besitzer:in darf Freigaben ändern." };
  }

  const [users, teams, roles] = await Promise.all([
    prisma.user.findMany({
      where: { id: { in: input.userIds.filter((id) => id !== ctx.userId) } },
      select: { id: true },
    }),
    prisma.team.findMany({ where: { id: { in: input.teamIds } }, select: { id: true } }),
    prisma.role.findMany({ where: { id: { in: input.roleIds } }, select: { id: true } }),
  ]);

  const base = target.folderId
    ? { folderId: target.folderId }
    : { fileId: target.fileId as string };

  await prisma.$transaction([
    prisma.cloudShare.deleteMany({ where: base }),
    prisma.cloudShare.createMany({
      data: [
        ...users.map((u) => ({ ...base, userId: u.id, canEdit: input.canEdit })),
        ...teams.map((t) => ({ ...base, teamId: t.id, canEdit: input.canEdit })),
        ...roles.map((r) => ({ ...base, roleId: r.id, canEdit: input.canEdit })),
      ],
    }),
  ]);

  revalidatePath("/cloud");
  return { ok: true };
}
