import { and, eq } from "drizzle-orm";
import { randomUUID } from "node:crypto";

import { db } from ".";
import env from "../../env";
import { createAuthInstance } from "../../lib/auth/factory";
import { account, user } from "./schemas/auth";

async function ensureSuperAdmin() {
  const email = env.SUPER_ADMIN_EMAIL;
  const password = env.SUPER_ADMIN_PASSWORD;
  const name = env.SUPER_ADMIN_NAME;

  if (!email || !password || !name) {
    throw new Error(
      "Las variables SUPER_ADMIN_EMAIL, SUPER_ADMIN_PASSWORD y SUPER_ADMIN_NAME deben estar definidas.",
    );
  }

  const auth = createAuthInstance({ disableEmail: true });
  const context = await auth.$context;

  // Configuración del proveedor de contraseñas
  const passwordConfig = (context.password?.config ?? {}) as {
    providerId?: string;
    getAccountId?: (identifier: string) => string;
  };

  const providerId = passwordConfig.providerId ?? "credential";

  // IMPORTANTE: el accountId debe ser el email sin transformaciones
  const accountIdentifier = email;

  console.log("providerId usado para cuentas:", providerId);
  console.log("accountIdentifier calculado:", accountIdentifier);

  // Verificar si el usuario ya existe
  const existingUser = await db.query.user.findFirst({
    where: eq(user.email, email),
  });

  if (existingUser) {
    console.log("Usuario existente encontrado:", existingUser.id);

    // Asegurar que tenga rol superAdmin
    if (existingUser.role !== "superAdmin") {
      await db
        .update(user)
        .set({ role: "superAdmin" })
        .where(eq(user.id, existingUser.id));
      console.log("Rol actualizado a superAdmin");
    }

    // Verificar si ya tiene una cuenta credential/email
    const existingAccount = await db.query.account.findFirst({
      where: and(
        eq(account.userId, existingUser.id),
        eq(account.providerId, providerId),
      ),
    });

    if (!existingAccount) {
      console.log("Creando cuenta de credenciales para usuario existente...");
      const passwordHash = await context.password.hash(password);
      await db.insert(account).values({
        id: randomUUID(),
        accountId: accountIdentifier,
        providerId,
        userId: existingUser.id,
        password: passwordHash,
        createdAt: new Date(),
        updatedAt: new Date(),
        accessToken: null,
        refreshToken: null,
        idToken: null,
        accessTokenExpiresAt: null,
        refreshTokenExpiresAt: null,
        scope: null,
      });
      console.log("Cuenta credential creada exitosamente");
    } else {
      console.log("La cuenta credential ya existe");
    }

    console.log(
      `El usuario ${email} ya existe con rol superAdmin y cuenta credential configurada.`,
    );
    return;
  }

  // Crear nuevo usuario con cuenta
  console.log("Creando nuevo super administrador...");
  const passwordHash = await context.password.hash(password);
  const now = new Date();
  const userId = randomUUID();
  const accountId = randomUUID();

  await db.transaction(async (tx) => {
    // Crear usuario
    await tx.insert(user).values({
      id: userId,
      name,
      email,
      emailVerified: true,
      image: null,
      createdAt: now,
      updatedAt: now,
      role: "superAdmin",
      banned: false,
      banReason: null,
      banExpires: null,
    });
    console.log("Usuario creado con ID:", userId);

    // Crear cuenta credential
    await tx.insert(account).values({
      id: accountId,
      accountId: accountIdentifier,
      providerId,
      userId,
      password: passwordHash,
      createdAt: now,
      updatedAt: now,
      accessToken: null,
      refreshToken: null,
      idToken: null,
      accessTokenExpiresAt: null,
      refreshTokenExpiresAt: null,
      scope: null,
    });
    console.log("Cuenta credential creada con ID:", accountId);
  });

  console.log(`✅ Super administrador creado exitosamente con ID ${userId}.`);
}

async function ensureRoleUser(
  role: "admin" | "user",
  overrides?: { email?: string; password?: string; name?: string },
) {
  const email =
    overrides?.email ??
    (role === "admin" ? "admin@example.com" : "user@example.com");
  const password = overrides?.password ?? "changeme";
  const name =
    overrides?.name ?? (role === "admin" ? "Demo Admin" : "Demo User");

  const auth = createAuthInstance({ disableEmail: true });
  const context = await auth.$context;

  const passwordConfig = (context.password?.config ?? {}) as {
    providerId?: string;
    getAccountId?: (identifier: string) => string;
  };
  const providerId = passwordConfig.providerId ?? "credential";
  const accountIdentifier = email;

  const existingUser = await db.query.user.findFirst({
    where: eq(user.email, email),
  });

  if (existingUser) {
    // Asegurar rol correcto
    if (existingUser.role !== role) {
      await db.update(user).set({ role }).where(eq(user.id, existingUser.id));
      console.log(`Rol actualizado a ${role} para ${email}`);
    }

    // Asegurar cuenta credential
    const existingAccount = await db.query.account.findFirst({
      where: and(
        eq(account.userId, existingUser.id),
        eq(account.providerId, providerId),
      ),
    });
    if (!existingAccount) {
      const passwordHash = await context.password.hash(password);
      await db.insert(account).values({
        id: randomUUID(),
        accountId: accountIdentifier,
        providerId,
        userId: existingUser.id,
        password: passwordHash,
        createdAt: new Date(),
        updatedAt: new Date(),
        accessToken: null,
        refreshToken: null,
        idToken: null,
        accessTokenExpiresAt: null,
        refreshTokenExpiresAt: null,
        scope: null,
      });
      console.log(`Cuenta credential creada para ${email}`);
    } else {
      console.log(`La cuenta credential ya existe para ${email}`);
    }
    console.log(`Usuario ${email} existe y está configurado como ${role}.`);
    return;
  }

  // Crear nuevo usuario demo
  console.log(`Creando usuario demo ${role}...`);
  const passwordHash = await context.password.hash(password);
  const now = new Date();
  const userId = randomUUID();
  const accountId = randomUUID();

  await db.transaction(async (tx) => {
    await tx.insert(user).values({
      id: userId,
      name,
      email,
      emailVerified: true,
      image: null,
      createdAt: now,
      updatedAt: now,
      role,
      banned: false,
      banReason: null,
      banExpires: null,
    });
    await tx.insert(account).values({
      id: accountId,
      accountId: accountIdentifier,
      providerId,
      userId,
      password: passwordHash,
      createdAt: now,
      updatedAt: now,
      accessToken: null,
      refreshToken: null,
      idToken: null,
      accessTokenExpiresAt: null,
      refreshTokenExpiresAt: null,
      scope: null,
    });
  });
  console.log(`✅ Usuario demo ${role} creado: ${email}`);
}

ensureSuperAdmin()
  .then(() => {
    // Crear usuarios de demostración con env si existen o fallback
    const adminOverrides = {
      email: env.ADMIN_EMAIL,
      password: env.ADMIN_PASSWORD,
      name: env.ADMIN_NAME,
    };
    const userOverrides = {
      email: env.USER_EMAIL,
      password: env.USER_PASSWORD,
      name: env.USER_NAME,
    };
    return Promise.all([
      ensureRoleUser("admin", adminOverrides),
      ensureRoleUser("user", userOverrides),
    ]);
  })
  .then(() => {
    console.log("✅ Seed de super administrador y usuarios demo completado.");
    process.exit(0);
  })
  .catch((error) => {
    console.error("❌ Error durante el seed de super administrador:", error);
    process.exit(1);
  });
