import "server-only";
import { prisma } from "@/lib/prisma";
import { getCloudScope, canReadFolder, canReadFile, canWriteFolder, type CloudScope } from "./access";

// ──────────────────────────────────────────────────────────────────────────
// Lesezugriffe des Cloud-Speichers.
// ──────────────────────────────────────────────────────────────────────────

export type CloudTarget = { id: string; name: string; color?: string | null };

export type FolderDTO = {
  id: string;
  name: string;
  color: string | null;
  icon: string | null;
  parentId: string | null;
  teamId: string | null;
  ownerName: string;
  isOwner: boolean;
  canWrite: boolean;
  fileCount: number;
  folderCount: number;
  shared: boolean;
  users: CloudTarget[];
  teams: CloudTarget[];
  roles: CloudTarget[];
  updatedAt: string;
};

export type FileDTO = {
  id: string;
  name: string;
  mime: string;
  size: number;
  width: number | null;
  height: number | null;
  folderId: string | null;
  ownerName: string;
  isOwner: boolean;
  canWrite: boolean;
  shared: boolean;
  users: CloudTarget[];
  teams: CloudTarget[];
  roles: CloudTarget[];
  createdAt: string;
};

export type Crumb = { id: string | null; name: string };

const dn = (u: { name: string; displayName: string | null }) => u.displayName ?? u.name;

const shareSelect = {
  select: {
    canEdit: true,
    user: { select: { id: true, name: true, displayName: true } },
    team: { select: { id: true, name: true, color: true } },
    role: { select: { id: true, name: true } },
  },
} as const;

type ShareRows = {
  canEdit: boolean;
  user: { id: string; name: string; displayName: string | null } | null;
  team: { id: string; name: string; color: string | null } | null;
  role: { id: string; name: string } | null;
}[];

function splitShares(shares: ShareRows) {
  return {
    users: shares.filter((s) => s.user).map((s) => ({ id: s.user!.id, name: dn(s.user!) })),
    teams: shares
      .filter((s) => s.team)
      .map((s) => ({ id: s.team!.id, name: s.team!.name, color: s.team!.color })),
    roles: shares.filter((s) => s.role).map((s) => ({ id: s.role!.id, name: s.role!.name })),
  };
}

/** Pfad von der Wurzel bis zum aktuellen Ordner. */
async function buildCrumbs(folderId: string | null): Promise<Crumb[]> {
  const crumbs: Crumb[] = [];
  let current = folderId;
  // Schutz gegen fehlerhafte Zyklen im Baum.
  for (let i = 0; current && i < 24; i++) {
    const row = await prisma.cloudFolder.findUnique({
      where: { id: current },
      select: { id: true, name: true, parentId: true },
    });
    if (!row) break;
    crumbs.unshift({ id: row.id, name: row.name });
    current = row.parentId;
  }
  return [{ id: null, name: "Ablage" }, ...crumbs];
}

export type CloudListing = {
  folderId: string | null;
  folderName: string;
  canWrite: boolean;
  crumbs: Crumb[];
  /** Automatische Team-Ordner — nur in der Wurzel. */
  teamFolders: FolderDTO[];
  folders: FolderDTO[];
  files: FileDTO[];
  scope: { readFolders: string[] };
};

/** Inhalt eines Ordners (oder der persönlichen Wurzel). */
/**
 * Legt für jedes Team des Nutzers einen Ordner an (einmalig) und hält Name
 * und Farbe mit dem Team synchron. Läuft nur beim Blick in die Wurzel.
 */
async function ensureTeamFolders(userId: string): Promise<void> {
  const teams = await prisma.team.findMany({
    where: { members: { some: { userId } } },
    select: { id: true, name: true, color: true },
  });

  for (const t of teams) {
    await prisma.cloudFolder.upsert({
      where: { teamId: t.id },
      update: { name: t.name, color: t.color },
      create: {
        teamId: t.id,
        name: t.name,
        color: t.color,
        icon: "users",
        parentId: null,
        ownerId: userId,
      },
    });
  }
}

export async function getCloudListing(
  userId: string,
  folderId: string | null,
): Promise<CloudListing | null> {
  if (folderId === null) await ensureTeamFolders(userId);
  const scope = await getCloudScope(userId);
  if (!canReadFolder(scope, folderId)) return null;

  const [folderRows, fileRows, current] = await Promise.all([
    prisma.cloudFolder.findMany({
      where: { parentId: folderId },
      orderBy: { name: "asc" },
      select: {
        id: true,
        name: true,
        color: true,
        icon: true,
        parentId: true,
        teamId: true,
        ownerId: true,
        updatedAt: true,
        owner: { select: { name: true, displayName: true } },
        shares: shareSelect,
        _count: { select: { files: true, children: true } },
      },
    }),
    prisma.cloudFile.findMany({
      where: { folderId },
      orderBy: { createdAt: "desc" },
      select: {
        id: true,
        name: true,
        mime: true,
        size: true,
        width: true,
        height: true,
        folderId: true,
        ownerId: true,
        createdAt: true,
        owner: { select: { name: true, displayName: true } },
        shares: shareSelect,
      },
    }),
    folderId
      ? prisma.cloudFolder.findUnique({ where: { id: folderId }, select: { name: true } })
      : Promise.resolve(null),
  ]);

  const mapped: FolderDTO[] = folderRows
    .filter((f) => f.ownerId === userId || scope.readFolders.has(f.id))
    .map((f) => {
      const parts = splitShares(f.shares as ShareRows);
      return {
        id: f.id,
        name: f.name,
        color: f.color,
        icon: f.icon,
        parentId: f.parentId,
        teamId: f.teamId,
        ownerName: dn(f.owner),
        isOwner: f.ownerId === userId,
        canWrite: f.ownerId === userId || scope.writeFolders.has(f.id),
        fileCount: f._count.files,
        folderCount: f._count.children,
        shared: f.shares.length > 0,
        ...parts,
        updatedAt: f.updatedAt.toISOString(),
      };
    });

  // Team-Ordner stehen in einer eigenen Kategorie.
  const teamFolders = mapped.filter((f) => f.teamId !== null);
  const folders = mapped.filter((f) => f.teamId === null);

  const files: FileDTO[] = fileRows
    .filter((f) => canReadFile(scope, { id: f.id, folderId: f.folderId, ownerId: f.ownerId }))
    .map((f) => {
      const parts = splitShares(f.shares as ShareRows);
      return {
        id: f.id,
        name: f.name,
        mime: f.mime,
        size: f.size,
        width: f.width,
        height: f.height,
        folderId: f.folderId,
        ownerName: dn(f.owner),
        isOwner: f.ownerId === userId,
        canWrite:
          f.ownerId === userId ||
          scope.writeFiles.has(f.id) ||
          (f.folderId !== null && scope.writeFolders.has(f.folderId)),
        shared: f.shares.length > 0,
        ...parts,
        createdAt: f.createdAt.toISOString(),
      };
    });

  return {
    folderId,
    folderName: current?.name ?? "Ablage",
    canWrite: canWriteFolder(scope, folderId),
    crumbs: await buildCrumbs(folderId),
    teamFolders,
    folders,
    files,
    scope: { readFolders: [...scope.readFolders] },
  };
}

/** Alle Ordner, in die verschoben werden darf (für den Zielordner-Wähler). */
export async function getWritableFolders(
  userId: string,
  scope?: CloudScope,
): Promise<{ id: string; name: string; parentId: string | null }[]> {
  const s = scope ?? (await getCloudScope(userId));
  const rows = await prisma.cloudFolder.findMany({
    orderBy: { name: "asc" },
    select: { id: true, name: true, parentId: true, ownerId: true },
  });
  return rows
    .filter((f) => f.ownerId === userId || s.writeFolders.has(f.id))
    .map(({ id, name, parentId }) => ({ id, name, parentId }));
}

/** Freigabe-Ziele (identisch zum Passwortmanager). */
export async function getCloudShareTargets() {
  const [users, teams, roles] = await Promise.all([
    prisma.user.findMany({
      where: { status: { not: "SUSPENDED" } },
      orderBy: { name: "asc" },
      select: { id: true, name: true, displayName: true, avatarUrl: true },
    }),
    prisma.team.findMany({ orderBy: { name: "asc" }, select: { id: true, name: true, color: true } }),
    prisma.role.findMany({ orderBy: { rank: "asc" }, select: { id: true, name: true } }),
  ]);
  return {
    users: users.map((u) => ({ id: u.id, name: dn(u), avatarUrl: u.avatarUrl })),
    teams,
    roles,
  };
}

export type CloudShareTargets = Awaited<ReturnType<typeof getCloudShareTargets>>;
