/**
 * Seed de CHESCO CARS. Idempotente: se puede ejecutar varias veces.
 *
 * 1. Permisos y roles (sincroniza la matriz de src/lib/auth/permissions.ts).
 * 2. Usuario SUPER_ADMIN inicial (SEED_ADMIN_EMAIL / SEED_ADMIN_PASSWORD).
 * 3. Configuración global con placeholders (nunca sobrescribe lo que ya editó un ADMIN).
 * 4. Datos DEMO opcionales (SEED_DEMO_DATA=true), marcados como demo. Nunca en producción.
 *
 * No inventa datos de la empresa: teléfono, dirección, RUC, redes, etc. quedan en null.
 */
import "dotenv/config";
import { randomBytes } from "node:crypto";
import { hash } from "@node-rs/argon2";
import { PrismaPg } from "@prisma/adapter-pg";
import { type Prisma, PrismaClient } from "@/generated/prisma/client";
import { ARGON2_OPTIONS } from "@/lib/auth/argon2-options";
import { PERMISSIONS, ROLE_DEFINITIONS, ROLE_KEYS } from "@/lib/auth/permissions";
import { newPasswordSchema } from "@/lib/validation/auth";
import { slugify, vehicleSlug } from "@/lib/text/slug";

const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) throw new Error("DATABASE_URL no está definido");

const db = new PrismaClient({ adapter: new PrismaPg({ connectionString: databaseUrl }) });
const isProduction = process.env.NODE_ENV === "production";

function randomPassword(): string {
  // 18 bytes → 24 caracteres base64url; se agrega un dígito para cumplir la política.
  return `${randomBytes(18).toString("base64url")}7`;
}

async function seedPermissionsAndRoles(): Promise<void> {
  for (const [key, def] of Object.entries(PERMISSIONS)) {
    await db.permission.upsert({
      where: { key },
      create: { key, module: def.module, description: def.description },
      update: { module: def.module, description: def.description },
    });
  }

  const permissionIds = new Map(
    (await db.permission.findMany({ select: { id: true, key: true } })).map((p) => [p.key, p.id]),
  );

  for (const roleKey of ROLE_KEYS) {
    const def = ROLE_DEFINITIONS[roleKey];
    const role = await db.role.upsert({
      where: { key: roleKey },
      create: { key: roleKey, name: def.name, description: def.description, isSystem: true },
      update: { name: def.name, description: def.description, isSystem: true },
    });
    const wanted = def.permissions.map((key) => {
      const id = permissionIds.get(key);
      if (!id) throw new Error(`Permiso inexistente en BD: ${key}`);
      return id;
    });
    await db.$transaction([
      db.rolePermission.deleteMany({ where: { roleId: role.id, permissionId: { notIn: wanted } } }),
      db.rolePermission.createMany({
        data: wanted.map((permissionId) => ({ roleId: role.id, permissionId })),
        skipDuplicates: true,
      }),
    ]);
    console.log(`  rol ${roleKey}: ${wanted.length} permisos`);
  }
}

async function upsertUser(params: {
  email: string;
  name: string;
  roleKey: (typeof ROLE_KEYS)[number];
  password: string;
  mustChangePassword: boolean;
}): Promise<"created" | "exists"> {
  const email = params.email.trim().toLowerCase();
  const existing = await db.user.findUnique({ where: { email }, select: { id: true } });
  if (existing) return "exists";
  const role = await db.role.findUniqueOrThrow({ where: { key: params.roleKey } });
  await db.user.create({
    data: {
      email,
      name: params.name,
      roleId: role.id,
      passwordHash: await hash(params.password, ARGON2_OPTIONS),
      mustChangePassword: params.mustChangePassword,
      passwordChangedAt: new Date(),
    },
  });
  return "created";
}

async function seedSuperAdmin(): Promise<void> {
  const email = process.env.SEED_ADMIN_EMAIL?.trim();
  const providedPassword = process.env.SEED_ADMIN_PASSWORD;

  if (!email) {
    console.warn("  SEED_ADMIN_EMAIL no definido: no se crea el SUPER_ADMIN inicial.");
    return;
  }
  if (providedPassword) {
    const policy = newPasswordSchema.safeParse(providedPassword);
    if (!policy.success) throw new Error(`SEED_ADMIN_PASSWORD: ${policy.error.issues[0]?.message}`);
  } else if (isProduction) {
    throw new Error("En producción SEED_ADMIN_PASSWORD es obligatorio.");
  }

  const password = providedPassword ?? randomPassword();
  const result = await upsertUser({
    email,
    name: "Super administrador",
    roleKey: "SUPER_ADMIN",
    password,
    // Contraseña generada o tomada de .env: se pide cambiarla en el primer ingreso.
    mustChangePassword: true,
  });
  if (result === "exists") {
    console.log(`  SUPER_ADMIN ${email} ya existe (contraseña sin cambios).`);
  } else if (providedPassword) {
    console.log(`  SUPER_ADMIN ${email} creado con la contraseña de SEED_ADMIN_PASSWORD.`);
  } else {
    console.log(
      `  SUPER_ADMIN ${email} creado. Contraseña temporal (solo se muestra ahora): ${password}`,
    );
  }
}

/** Valores iniciales. `update: {}` → nunca pisa lo que se haya configurado desde el panel. */
const DEFAULT_SETTINGS: { key: string; value: Prisma.InputJsonValue; isPublic: boolean }[] = [
  {
    key: "company",
    isPublic: true,
    value: {
      name: "CHESCO CARS",
      claim: "COMPRA • VENTA • CONSIGNACIÓN",
      legalName: null,
      ruc: null,
      phone: null,
      email: null,
      address: null,
      mapUrl: null,
      schedule: null,
    },
  },
  {
    key: "whatsapp",
    isPublic: true,
    value: { number: process.env.WHATSAPP_NUMBER?.trim() || null },
  },
  {
    key: "social",
    isPublic: true,
    value: { facebook: null, instagram: null, tiktok: null },
  },
  {
    key: "seo",
    isPublic: true,
    value: {
      defaultTitle: "CHESCO CARS | Compra • Venta • Consignación",
      defaultDescription: null,
    },
  },
  {
    key: "commissions.advisorDefault",
    isPublic: false,
    // Sin comisión por defecto hasta que ADMIN defina la política.
    value: { type: "NONE", value: "0" },
  },
  { key: "vehicles.showPlateDefault", isPublic: false, value: false },
  { key: "vehicles.soldVisibleDays", isPublic: false, value: 15 },
  { key: "media.watermark", isPublic: false, value: { enabled: false } },
  { key: "analytics", isPublic: true, value: { gaMeasurementId: null, metaPixelId: null } },
];

async function seedSettings(): Promise<void> {
  for (const setting of DEFAULT_SETTINGS) {
    await db.setting.upsert({
      where: { key: setting.key },
      create: setting,
      update: {},
    });
  }
  console.log(`  ${DEFAULT_SETTINGS.length} claves de configuración`);
}

const DEMO_FEATURES: {
  name: string;
  category: "EQUIPMENT" | "SAFETY" | "COMFORT" | "TECHNOLOGY";
}[] = [
  { name: "Aire acondicionado", category: "COMFORT" },
  { name: "Cámara de retroceso", category: "SAFETY" },
  { name: "Airbags frontales", category: "SAFETY" },
  { name: "Frenos ABS", category: "SAFETY" },
  { name: "Pantalla táctil", category: "TECHNOLOGY" },
  { name: "Apple CarPlay / Android Auto", category: "TECHNOLOGY" },
  { name: "Aros de aleación", category: "EQUIPMENT" },
  { name: "Sensores de estacionamiento", category: "SAFETY" },
];

type DemoVehicle = {
  code: string;
  brand: string;
  model: string;
  version: string;
  year: number;
  price: string;
  currency: "USD" | "PEN";
  mileageKm: number;
  transmission: "MANUAL" | "AUTOMATIC" | "CVT";
  fuelType: "GASOLINE" | "DIESEL" | "HYBRID";
  bodyType: "SUV" | "SEDAN" | "HATCHBACK" | "PICKUP" | "SPORTS" | "VAN";
  color: string;
  status: "AVAILABLE" | "RESERVED" | "COMING_SOON";
  isFeatured: boolean;
};

const DEMO_VEHICLES: DemoVehicle[] = [
  {
    code: "DEMO-001",
    brand: "Toyota",
    model: "Corolla Cross",
    version: "XEI",
    year: 2025,
    price: "24900",
    currency: "USD",
    mileageKm: 18450,
    transmission: "AUTOMATIC",
    fuelType: "GASOLINE",
    bodyType: "SUV",
    color: "Blanco",
    status: "AVAILABLE",
    isFeatured: true,
  },
  {
    code: "DEMO-002",
    brand: "Hyundai",
    model: "Tucson",
    version: "GLS",
    year: 2023,
    price: "26500",
    currency: "USD",
    mileageKm: 32100,
    transmission: "AUTOMATIC",
    fuelType: "GASOLINE",
    bodyType: "SUV",
    color: "Gris",
    status: "AVAILABLE",
    isFeatured: true,
  },
  {
    code: "DEMO-003",
    brand: "Kia",
    model: "Rio",
    version: "EX",
    year: 2022,
    price: "54900",
    currency: "PEN",
    mileageKm: 41200,
    transmission: "MANUAL",
    fuelType: "GASOLINE",
    bodyType: "HATCHBACK",
    color: "Rojo",
    status: "AVAILABLE",
    isFeatured: false,
  },
  {
    code: "DEMO-004",
    brand: "Toyota",
    model: "Hilux",
    version: "SRV 4x4",
    year: 2021,
    price: "33900",
    currency: "USD",
    mileageKm: 67800,
    transmission: "MANUAL",
    fuelType: "DIESEL",
    bodyType: "PICKUP",
    color: "Plata",
    status: "RESERVED",
    isFeatured: true,
  },
  {
    code: "DEMO-005",
    brand: "Mazda",
    model: "3",
    version: "Grand Touring",
    year: 2024,
    price: "89900",
    currency: "PEN",
    mileageKm: 9800,
    transmission: "AUTOMATIC",
    fuelType: "GASOLINE",
    bodyType: "SEDAN",
    color: "Negro",
    status: "AVAILABLE",
    isFeatured: false,
  },
  {
    code: "DEMO-006",
    brand: "Hyundai",
    model: "Staria",
    version: "Van 12 pasajeros",
    year: 2023,
    price: "41500",
    currency: "USD",
    mileageKm: 25300,
    transmission: "AUTOMATIC",
    fuelType: "DIESEL",
    bodyType: "VAN",
    color: "Blanco",
    status: "COMING_SOON",
    isFeatured: false,
  },
];

async function seedDemoData(): Promise<void> {
  const demoPassword = process.env.SEED_DEMO_PASSWORD ?? randomPassword();
  const demoUsers = [
    {
      email: "supervisor@demo.chesco.local",
      name: "Supervisor DEMO",
      roleKey: "SUPERVISOR" as const,
    },
    { email: "asesor1@demo.chesco.local", name: "Asesor DEMO 1", roleKey: "ADVISOR" as const },
    { email: "asesor2@demo.chesco.local", name: "Asesor DEMO 2", roleKey: "ADVISOR" as const },
  ];
  let createdUsers = 0;
  for (const user of demoUsers) {
    const result = await upsertUser({ ...user, password: demoPassword, mustChangePassword: false });
    if (result === "created") createdUsers += 1;
  }
  if (createdUsers > 0) {
    console.log(
      `  ${createdUsers} usuarios DEMO creados (${demoUsers.map((u) => u.email).join(", ")}).` +
        (process.env.SEED_DEMO_PASSWORD
          ? " Contraseña: SEED_DEMO_PASSWORD."
          : ` Contraseña (solo se muestra ahora): ${demoPassword}`),
    );
  }

  for (const feature of DEMO_FEATURES) {
    await db.feature.upsert({
      where: { name_category: { name: feature.name, category: feature.category } },
      create: feature,
      update: {},
    });
  }
  const features = await db.feature.findMany({ select: { id: true } });

  for (const v of DEMO_VEHICLES) {
    const brand = await db.brand.upsert({
      where: { slug: slugify(v.brand) },
      create: { name: v.brand, slug: slugify(v.brand) },
      update: {},
    });
    const model = await db.vehicleModel.upsert({
      where: { brandId_slug: { brandId: brand.id, slug: slugify(v.model) } },
      create: { brandId: brand.id, name: v.model, slug: slugify(v.model) },
      update: {},
    });
    const exists = await db.vehicle.findUnique({ where: { code: v.code }, select: { id: true } });
    if (exists) continue;
    const vehicle = await db.vehicle.create({
      data: {
        code: v.code,
        slug: vehicleSlug({ brand: v.brand, model: v.model, version: v.version, year: v.year }),
        brandId: brand.id,
        modelId: model.id,
        version: v.version,
        year: v.year,
        price: v.price,
        currency: v.currency,
        mileageKm: v.mileageKm,
        transmission: v.transmission,
        fuelType: v.fuelType,
        bodyType: v.bodyType,
        color: v.color,
        status: v.status,
        isFeatured: v.isFeatured,
        isDemo: true,
        publishedAt: v.status === "COMING_SOON" ? null : new Date(),
        description:
          "VEHÍCULO DE DEMOSTRACIÓN. Datos ficticios para desarrollo; no corresponde a un vehículo real en venta.",
        features: {
          create: features.slice(0, 5).map((f) => ({ featureId: f.id })),
        },
        statusHistory: { create: { toStatus: v.status, reason: "Seed de demostración" } },
      },
    });
    console.log(`  vehículo DEMO ${v.code} → /vehiculos/${vehicle.slug}`);
  }
}

async function main(): Promise<void> {
  console.log("Seed CHESCO CARS");
  console.log("• Permisos y roles");
  await seedPermissionsAndRoles();
  console.log("• Super administrador");
  await seedSuperAdmin();
  console.log("• Configuración");
  await seedSettings();

  const wantsDemo = (process.env.SEED_DEMO_DATA ?? "false").toLowerCase() === "true";
  if (wantsDemo && isProduction) {
    console.warn("• Datos DEMO omitidos: no se cargan en producción.");
  } else if (wantsDemo) {
    console.log("• Datos DEMO");
    await seedDemoData();
  }
  console.log("Listo.");
}

main()
  .catch((error: unknown) => {
    console.error(error);
    process.exitCode = 1;
  })
  .finally(() => {
    void db.$disconnect();
  });
