'use strict';

/**
 * Migration to add foreign key constraints to all model associations.
 * This enforces referential integrity at the database level.
 */

module.exports = {
  async up(queryInterface) {
    const transaction = await queryInterface.sequelize.transaction();

    try {
      // Helper to add FK constraint safely (checks if exists first)
      const addForeignKey = async (
        tableName,
        columnName,
        references,
        onDelete = 'CASCADE',
        onUpdate = 'CASCADE',
      ) => {
        const constraintName = `${tableName}_${columnName}_fkey`;

        // Check if constraint already exists
        const [results] = await queryInterface.sequelize.query(
          `SELECT constraint_name FROM information_schema.table_constraints
           WHERE table_name = '${tableName}' AND constraint_name = '${constraintName}'`,
          { transaction },
        );

        if (results.length === 0) {
          await queryInterface.addConstraint(tableName, {
            fields: [columnName],
            type: 'foreign key',
            name: constraintName,
            references: {
              table: references.table,
              field: references.field,
            },
            onDelete,
            onUpdate,
            transaction,
          });
          console.log(`Added FK constraint: ${constraintName}`);
        } else {
          console.log(`FK constraint already exists: ${constraintName}`);
        }
      };

      // asset_variants -> assets
      await addForeignKey(
        'asset_variants',
        'assetId',
        { table: 'assets', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // page_elements -> tour_pages
      await addForeignKey(
        'page_elements',
        'pageId',
        { table: 'tour_pages', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // page_links -> tour_pages (from_page)
      await addForeignKey(
        'page_links',
        'from_pageId',
        { table: 'tour_pages', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // page_links -> tour_pages (to_page)
      await addForeignKey(
        'page_links',
        'to_pageId',
        { table: 'tour_pages', field: 'id' },
        'SET NULL',
        'CASCADE',
      );

      // page_links -> transitions
      await addForeignKey(
        'page_links',
        'transitionId',
        { table: 'transitions', field: 'id' },
        'SET NULL',
        'CASCADE',
      );

      // assets -> projects
      await addForeignKey(
        'assets',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // tour_pages -> projects
      await addForeignKey(
        'tour_pages',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // transitions -> projects
      await addForeignKey(
        'transitions',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // project_memberships -> projects
      await addForeignKey(
        'project_memberships',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // project_memberships -> users
      await addForeignKey(
        'project_memberships',
        'userId',
        { table: 'users', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // presigned_url_requests -> projects
      await addForeignKey(
        'presigned_url_requests',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // presigned_url_requests -> users
      await addForeignKey(
        'presigned_url_requests',
        'userId',
        { table: 'users', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // project_audio_tracks -> projects
      await addForeignKey(
        'project_audio_tracks',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // publish_events -> projects
      await addForeignKey(
        'publish_events',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // publish_events -> users (SET NULL to preserve audit trail)
      await addForeignKey(
        'publish_events',
        'userId',
        { table: 'users', field: 'id' },
        'SET NULL',
        'CASCADE',
      );

      // pwa_caches -> projects
      await addForeignKey(
        'pwa_caches',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // access_logs -> projects
      await addForeignKey(
        'access_logs',
        'projectId',
        { table: 'projects', field: 'id' },
        'CASCADE',
        'CASCADE',
      );

      // access_logs -> users (SET NULL to preserve audit trail)
      await addForeignKey(
        'access_logs',
        'userId',
        { table: 'users', field: 'id' },
        'SET NULL',
        'CASCADE',
      );

      // users -> roles (SET NULL so deleting role doesn't delete users)
      await addForeignKey(
        'users',
        'app_roleId',
        { table: 'roles', field: 'id' },
        'SET NULL',
        'CASCADE',
      );

      await transaction.commit();
      console.log('All FK constraints added successfully');
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  },

  async down(queryInterface) {
    const transaction = await queryInterface.sequelize.transaction();

    try {
      const dropForeignKey = async (tableName, columnName) => {
        const constraintName = `${tableName}_${columnName}_fkey`;
        try {
          await queryInterface.removeConstraint(tableName, constraintName, {
            transaction,
          });
          console.log(`Removed FK constraint: ${constraintName}`);
        } catch (error) {
          console.log(
            `FK constraint not found (may not exist): ${constraintName}`,
          );
        }
      };

      // Remove all FK constraints in reverse order
      await dropForeignKey('users', 'app_roleId');
      await dropForeignKey('access_logs', 'userId');
      await dropForeignKey('access_logs', 'projectId');
      await dropForeignKey('pwa_caches', 'projectId');
      await dropForeignKey('publish_events', 'userId');
      await dropForeignKey('publish_events', 'projectId');
      await dropForeignKey('project_audio_tracks', 'projectId');
      await dropForeignKey('presigned_url_requests', 'userId');
      await dropForeignKey('presigned_url_requests', 'projectId');
      await dropForeignKey('project_memberships', 'userId');
      await dropForeignKey('project_memberships', 'projectId');
      await dropForeignKey('transitions', 'projectId');
      await dropForeignKey('tour_pages', 'projectId');
      await dropForeignKey('assets', 'projectId');
      await dropForeignKey('page_links', 'transitionId');
      await dropForeignKey('page_links', 'to_pageId');
      await dropForeignKey('page_links', 'from_pageId');
      await dropForeignKey('page_elements', 'pageId');
      await dropForeignKey('asset_variants', 'assetId');

      await transaction.commit();
      console.log('All FK constraints removed successfully');
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  },
};
