import bcrypt from 'bcrypt';
import {
  Op,
  QueryTypes,
  type CreationAttributes,
  type QueryInterface,
} from 'sequelize';
import config from '@/shared/config';
import { ROLE_NAMES } from '@/shared/constants/roles';
import { SEED_ALL_USERS } from '@/shared/constants/seed-fixtures';
import type { Users } from '@/db/models/users';

/** Documented seed credentials - see CLAUDE.md for reference. */
const SEED_DEFAULTS: Record<string, string> = {
  SEED_ADMIN_PASSWORD: 'flatlogicAdmin123!',
  SEED_USER_PASSWORD: 'flatlogicUser123!',
  SEED_ADMIN_EMAIL: 'admin@flatlogic.com',
};

function seedEnv(name: string): string {
  return process.env[name] || SEED_DEFAULTS[name] || '';
}

const ids = SEED_ALL_USERS.map((user) => user.id);

/**
 * Seeds the RBAC fixture users — exactly one per stored role (Workstream 4).
 * `admin@flatlogic.com` (`SEED_ADMIN_EMAIL`) is the super admin. Roles, org, and
 * campus links are applied by later seeders. Idempotent: skips ids already present.
 */
export default {
  up: async (queryInterface: QueryInterface) => {
    const adminHash = bcrypt.hashSync(
      seedEnv('SEED_ADMIN_PASSWORD'),
      config.bcrypt.saltRounds,
    );
    const userHash = bcrypt.hashSync(
      seedEnv('SEED_USER_PASSWORD'),
      config.bcrypt.saltRounds,
    );
    const adminEmail = seedEnv('SEED_ADMIN_EMAIL');
    const createdAt = new Date();
    const updatedAt = new Date();

    const rows: CreationAttributes<Users>[] = SEED_ALL_USERS.map((user) => ({
      id: user.id,
      name_prefix: user.namePrefix ?? null,
      firstName: user.firstName,
      lastName: user.lastName,
      // The super admin uses the configured SEED_ADMIN_EMAIL for login.
      email: user.role === ROLE_NAMES.SUPER_ADMIN ? adminEmail : user.email,
      emailVerified: true,
      provider: config.providers.LOCAL,
      password: user.admin ? adminHash : userHash,
      createdAt,
      updatedAt,
    }));

    const existing = await queryInterface.sequelize.query<{ id: string }>(
      `SELECT id FROM users WHERE id IN (:ids)`,
      { replacements: { ids }, type: QueryTypes.SELECT },
    );
    const existingIds = new Set(existing.map((row) => row.id));
    const toInsert = rows.filter((row) => !existingIds.has(row.id as string));

    if (toInsert.length > 0) {
      await queryInterface.bulkInsert('users', toInsert);
    }
  },

  down: async (queryInterface: QueryInterface) => {
    await queryInterface.bulkDelete('users', { id: { [Op.in]: ids } }, {});
  },
};
