// ──────────────────────────────────────────────────────────────────────────
// Seed für Avaria Team OS.
//
// Legt ausschließlich das an, was das System zum Betrieb braucht:
//   • alle Berechtigungen aus dem RBAC-Katalog
//   • die System-Rollen samt Rechtezuordnung
//   • ein Administrator-Konto aus der .env
//
// Bewusst KEINE Demo- oder Beispieldaten: keine Projekte, Boards, Creator,
// Kanäle oder Testnutzer. Der Seed ist idempotent und kann nach jedem Update
// erneut laufen.
// ──────────────────────────────────────────────────────────────────────────

import { PrismaClient } from "@prisma/client";
import { hash } from "@node-rs/argon2";
import {
  ROLES,
  PERMISSIONS,
  resolveRolePermissions,
  type RoleKey,
} from "../src/lib/rbac/catalog.ts";

const prisma = new PrismaClient();

const ARGON2 = { memoryCost: 19456, timeCost: 2, parallelism: 1 } as const;

async function main() {
  // ── Berechtigungen ────────────────────────────────────────────────────────
  console.log("→ Seede Berechtigungen …");
  for (const [key, def] of Object.entries(PERMISSIONS)) {
    await prisma.permission.upsert({
      where: { key },
      update: { module: def.module, description: def.description },
      create: { key, module: def.module, description: def.description },
    });
  }

  // Typ bewusst ausgeschrieben: So lässt sich der Seed auch dann prüfen und
  // bauen, wenn der Prisma-Client noch nicht aus dem Schema erzeugt wurde.
  const permRows: { id: string; key: string }[] = await prisma.permission.findMany({
    select: { id: true, key: true },
  });
  const permIdByKey = new Map(permRows.map((p) => [p.key, p.id]));

  // ── Rollen & Zuordnungen ──────────────────────────────────────────────────
  console.log("→ Seede Rollen & Zuordnungen …");
  for (const [key, def] of Object.entries(ROLES)) {
    const role = await prisma.role.upsert({
      where: { key },
      update: { name: def.name, description: def.description, rank: def.rank, isSystem: true },
      create: { key, name: def.name, description: def.description, rank: def.rank, isSystem: true },
    });

    const permKeys = resolveRolePermissions(key as RoleKey);
    // Zuordnungen neu setzen (idempotent).
    await prisma.rolePermission.deleteMany({ where: { roleId: role.id } });
    await prisma.rolePermission.createMany({
      data: permKeys
        .map((pk) => permIdByKey.get(pk))
        .filter((id): id is string => Boolean(id))
        .map((permissionId) => ({ roleId: role.id, permissionId })),
    });
  }

  // ── Admin-Konto aus der Umgebung ──────────────────────────────────────────
  console.log("→ Seede Admin-Konto (aus .env) …");
  const adminEmail = process.env.ADMIN_EMAIL?.trim().toLowerCase();
  const adminPassword = process.env.ADMIN_PASSWORD;
  if (!adminEmail || !adminPassword) {
    throw new Error(
      "ADMIN_EMAIL und ADMIN_PASSWORD müssen in der .env gesetzt sein, damit ein Admin-Konto angelegt werden kann.",
    );
  }

  const adminHash = await hash(adminPassword, ARGON2);
  const adminUser = await prisma.user.upsert({
    where: { email: adminEmail },
    // Bootstrap: Passwort wird beim Seed auf den .env-Wert gesetzt.
    update: { status: "ACTIVE", passwordHash: adminHash },
    create: {
      email: adminEmail,
      name: process.env.ADMIN_NAME?.trim() || "Administrator",
      jobTitle: "Administration",
      passwordHash: adminHash,
      status: "ACTIVE",
    },
  });

  const adminRole = await prisma.role.findUnique({ where: { key: "ADMIN" } });
  if (adminRole) {
    await prisma.userRole.upsert({
      where: { userId_roleId: { userId: adminUser.id, roleId: adminRole.id } },
      update: {},
      create: { userId: adminUser.id, roleId: adminRole.id },
    });
  }

  console.log(`\n✔ Seed abgeschlossen. Admin-Konto: ${adminEmail}`);
}

main()
  .catch((e) => {
    console.error(e);
    process.exitCode = 1;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
