import { v4 as uuid } from 'uuid';
import type { QueryInterface } from 'sequelize';
import { ROLE_NAMES } from '@/shared/constants/roles';
import { FEATURE_PERMISSIONS } from '@/shared/constants/product-permissions';

function isIdRow(value: unknown): value is { id: string } {
  return (
    value !== null
    && typeof value === 'object'
    && 'id' in value
    && typeof value.id === 'string'
  );
}

function firstId(value: unknown): string | null {
  return Array.isArray(value) ? value.find(isIdRow)?.id ?? null : null;
}

function resultRows(value: unknown): unknown[] {
  return Array.isArray(value) ? value : [];
}

export default {
  up: async (queryInterface: QueryInterface) => {
    const now = new Date();
    const [permissionRows] = await queryInterface.sequelize.query(
      'SELECT "id" FROM "permissions" WHERE "name" = :name LIMIT 1',
      { replacements: { name: FEATURE_PERMISSIONS.ZONE_CHECKIN } },
    );
    let permissionId = firstId(permissionRows);

    if (!permissionId) {
      permissionId = uuid();
      await queryInterface.bulkInsert('permissions', [{
        id: permissionId,
        name: FEATURE_PERMISSIONS.ZONE_CHECKIN,
        createdAt: now,
        updatedAt: now,
      }]);
    }

    const [roleRows] = await queryInterface.sequelize.query(
      'SELECT "id" FROM "roles" WHERE "name" = :name LIMIT 1',
      { replacements: { name: ROLE_NAMES.REGISTRAR } },
    );
    const roleId = firstId(roleRows);

    if (!roleId) {
      return;
    }

    const [existingRows] = await queryInterface.sequelize.query(
      `SELECT 1 FROM "rolesPermissionsPermissions"
       WHERE "roles_permissionsId" = :roleId AND "permissionId" = :permissionId
       LIMIT 1`,
      { replacements: { roleId, permissionId } },
    );

    if (resultRows(existingRows).length === 0) {
      await queryInterface.bulkInsert('rolesPermissionsPermissions', [{
        createdAt: now,
        updatedAt: now,
        roles_permissionsId: roleId,
        permissionId,
      }]);
    }
  },

  down: async () => {
    // Keep permission grants on rollback; permissions may be assigned manually.
  },
};
