require("dotenv").config({ path: ".env" });

const prisma = require("../src/prisma");
const bcrypt = require("bcrypt");
const { PERMISSION_CATALOG } = require("../src/lib/permissionCatalog");

const MIN_SUPERADMIN_PASSWORD_LENGTH = 12;

async function main() {
  const userRole = await prisma.role.upsert({
    where: { name: "User" },
    update: {},
    create: { name: "User" },
  });

  const adminRole = await prisma.role.upsert({
    where: { name: "Admin" },
    update: {},
    create: { name: "Admin" },
  });

  const superAdminRole = await prisma.role.upsert({
    where: { name: "Super Admin" },
    update: {},
    create: { name: "Super Admin" },
  });

  for (const p of PERMISSION_CATALOG) {
    await prisma.permission.upsert({
      where: { name: p.name },
      update: {
        label: p.label,
        description: p.description,
        category: p.category,
        sortOrder: p.sortOrder,
        isSystem: true,
      },
      create: {
        name: p.name,
        label: p.label,
        description: p.description,
        category: p.category,
        sortOrder: p.sortOrder,
        isSystem: true,
      },
    });
  }

  // Give Admin all permissions
  const allPerms = await prisma.permission.findMany({ select: { id: true } });
  await prisma.rolePermission.deleteMany({ where: { roleId: adminRole.id } });
  await prisma.rolePermission.createMany({
    data: allPerms.map((p) => ({ roleId: adminRole.id, permissionId: p.id })),
    skipDuplicates: true,
  });

  // Give Super Admin all permissions
  await prisma.rolePermission.deleteMany({ where: { roleId: superAdminRole.id } });
  await prisma.rolePermission.createMany({
    data: allPerms.map((p) => ({ roleId: superAdminRole.id, permissionId: p.id })),
    skipDuplicates: true,
  });

  // Give User basic read permissions
  const basicPerms = await prisma.permission.findMany({
    where: { name: { in: ["pos:read", "inventory:read"] } },
    select: { id: true },
  });
  await prisma.rolePermission.deleteMany({ where: { roleId: userRole.id } });
  await prisma.rolePermission.createMany({
    data: basicPerms.map((p) => ({ roleId: userRole.id, permissionId: p.id })),
    skipDuplicates: true,
  });

  // Seed Super Admin user (idempotent) from env vars
  const email = (process.env.SUPERADMIN_EMAIL || "").trim();
  const username = (process.env.SUPERADMIN_USERNAME || "superadmin").trim() || "superadmin";
  const password = process.env.SUPERADMIN_PASSWORD || "";
  const fullName = (process.env.SUPERADMIN_FULL_NAME || "").trim();

  if (!email || !password || !fullName) return;
  if (password.length < MIN_SUPERADMIN_PASSWORD_LENGTH) return;

  const mainBranch = await prisma.branch.upsert({
    where: { name: "Main Branch" },
    update: {},
    create: { name: "Main Branch", code: "MAIN" },
  });

  const existing = await prisma.user.findUnique({ where: { email } });
  if (existing) {
    await prisma.userBranch.upsert({
      where: { userId_branchId: { userId: existing.id, branchId: mainBranch.id } },
      update: {},
      create: { userId: existing.id, branchId: mainBranch.id },
    });
    if (!existing.activeBranchId) {
      await prisma.user.update({
        where: { id: existing.id },
        data: { activeBranchId: mainBranch.id },
      });
    }
    return;
  }

  const passwordHash = await bcrypt.hash(password, 10);
  const user = await prisma.user.create({
    data: {
      email,
      fullName,
      username,
      passwordHash,
      isVerified: true,
      isApproved: true,
      activeBranchId: mainBranch.id,
      roles: { create: [{ roleId: superAdminRole.id }] },
      branches: { create: [{ branchId: mainBranch.id }] },
    },
    select: { id: true, email: true },
  });

  // eslint-disable-next-line no-console
  console.log(`Superadmin seeded: ${user.email}`);
}

async function migrateWarehouseStock() {
  const existing = await prisma.warehouseStock.count();
  if (existing > 0) return;

  const products = await prisma.product.findMany({
    where: { deletedAt: null, quantity: { gt: 0 } },
    select: { id: true, quantity: true, warehouseId: true },
  });
  if (products.length === 0) return;

  let defaultWh = await prisma.warehouse.findFirst({
    orderBy: [{ sortOrder: "asc" }, { name: "asc" }],
  });
  if (!defaultWh) {
    const branch = await prisma.branch.findFirst({ orderBy: [{ sortOrder: "asc" }, { name: "asc" }] });
    defaultWh = await prisma.warehouse.create({
      data: { name: "Main Warehouse", branchId: branch?.id || null },
    });
  }

  for (const p of products) {
    const warehouseId = p.warehouseId || defaultWh.id;
    await prisma.warehouseStock.upsert({
      where: { warehouseId_productId: { warehouseId, productId: p.id } },
      create: { warehouseId, productId: p.id, quantity: p.quantity },
      update: { quantity: p.quantity },
    });
  }
  // eslint-disable-next-line no-console
  console.log(`Migrated ${products.length} product(s) to warehouse stock`);
}

async function migrateBranchData() {
  const branch = await prisma.branch.findFirst({ orderBy: [{ sortOrder: "asc" }, { name: "asc" }] });
  if (!branch) return;

  const branchId = branch.id;
  const models = [
    "product",
    "sale",
    "salesReturn",
    "purchase",
    "purchaseReturn",
    "invoice",
    "customer",
    "supplier",
    "expenseCategory",
    "expense",
    "inventoryAdjustment",
    "inventoryTransfer",
    "category",
    "brand",
    "unit",
    "variation",
    "tax",
    "warehouse",
    "paymentMethod",
  ];

  for (const m of models) {
    // eslint-disable-next-line no-await-in-loop
    await prisma[m].updateMany({
      where: { branchId: null },
      data: { branchId },
    }).catch(() => {});
  }
}

main()
  .then(async () => {
    await migrateWarehouseStock();
    await migrateBranchData();
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    // eslint-disable-next-line no-console
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });

