'use strict';

// Helper function to safely create a table if it doesn't exist
async function createTableIfNotExists(queryInterface, tableName, tableDefinition) {
  const tableExists = await queryInterface.tableExists(tableName);
  if (!tableExists) {
    await queryInterface.createTable(tableName, tableDefinition);
  }
}

// Helper function to safely add a column if it doesn't exist
async function addColumnIfNotExists(queryInterface, tableName, columnName, columnDefinition) {
  const tableDescription = await queryInterface.describeTable(tableName);
  if (!tableDescription[columnName]) {
    await queryInterface.addColumn(tableName, columnName, columnDefinition);
  }
}

// Helper function to safely add an index if it doesn't exist
async function addIndexIfNotExists(queryInterface, tableName, fields, options) {
  try {
    const tableExists = await queryInterface.tableExists(tableName);
    if (!tableExists) {
      return;
    }

    const indexes = await queryInterface.showIndex(tableName);
    const indexName = options.name || `idx_${tableName}_${fields.join('_')}`;
    const indexExists = indexes.some(idx => idx.name === indexName);
    if (!indexExists) {
      await queryInterface.addIndex(tableName, fields, options);
    }
  } catch (error) {
    if (
      error.message &&
      (error.message.includes('already exists') || error.message.includes('duplicate key value'))
    ) {
      return;
    }
    throw error;
  }
}

module.exports = {
  async up(queryInterface, Sequelize) {
    // Create cloud_providers table
    await createTableIfNotExists(queryInterface, 'cloud_providers', {
      id: {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        primaryKey: true,
      },
      name: {
        type: Sequelize.STRING(255),
        allowNull: false,
        comment: 'Display name for the cloud provider',
      },
      provider_type: {
        type: Sequelize.STRING(50),
        allowNull: false,
        comment: 'Type of provider: browserstack, lambdatest, saucelabs, custom',
      },
      base_url: {
        type: Sequelize.STRING(500),
        allowNull: false,
        comment: 'WebDriver hub URL for the provider',
      },
      username: {
        type: Sequelize.STRING(255),
        allowNull: false,
        comment: 'Username or access key ID',
      },
      access_key_encrypted: {
        type: Sequelize.TEXT,
        allowNull: false,
        comment: 'Encrypted access key/secret',
      },
      is_active: {
        type: Sequelize.BOOLEAN,
        defaultValue: true,
        allowNull: false,
        comment: 'Whether this provider is active',
      },
      organization_id: {
        type: Sequelize.UUID,
        allowNull: false,
        references: {
          model: 'organizations',
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
        comment: 'Organization that owns this provider',
      },
      created_by: {
        type: Sequelize.UUID,
        allowNull: false,
        references: {
          model: 'users',
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
        comment: 'User who created this provider',
      },
      metadata: {
        type: Sequelize.TEXT,
        allowNull: true,
        comment: 'JSON metadata for extra configuration',
      },
      created_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.NOW,
        allowNull: false,
      },
      updated_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.NOW,
        allowNull: false,
      },
    });

    // Add indexes for cloud_providers
    await addIndexIfNotExists(queryInterface, 'cloud_providers', ['organization_id'], {
      name: 'idx_cloud_providers_organization_id',
    });
    await addIndexIfNotExists(queryInterface, 'cloud_providers', ['provider_type'], {
      name: 'idx_cloud_providers_provider_type',
    });
    await addIndexIfNotExists(queryInterface, 'cloud_providers', ['is_active'], {
      name: 'idx_cloud_providers_is_active',
    });

    // Create cloud_devices table
    await createTableIfNotExists(queryInterface, 'cloud_devices', {
      id: {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        primaryKey: true,
      },
      cloud_provider_id: {
        type: Sequelize.UUID,
        allowNull: false,
        references: {
          model: 'cloud_providers',
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
        comment: 'Cloud provider this device belongs to',
      },
      name: {
        type: Sequelize.STRING(255),
        allowNull: false,
        comment: 'Display name for the device',
      },
      platform: {
        type: Sequelize.STRING(50),
        allowNull: false,
        comment: 'Platform: android or ios',
      },
      platform_version: {
        type: Sequelize.STRING(50),
        allowNull: false,
        comment: 'OS version (e.g., 16.0, 13)',
      },
      device_name: {
        type: Sequelize.STRING(255),
        allowNull: false,
        comment: 'Provider-specific device name',
      },
      capabilities_template: {
        type: Sequelize.TEXT,
        allowNull: true,
        comment: 'JSON default capabilities for this device',
      },
      is_active: {
        type: Sequelize.BOOLEAN,
        defaultValue: true,
        allowNull: false,
        comment: 'Whether this device is active',
      },
      is_busy: {
        type: Sequelize.BOOLEAN,
        defaultValue: false,
        allowNull: false,
        comment: 'Whether this device is currently in use',
      },
      active_session_id: {
        type: Sequelize.STRING(255),
        allowNull: true,
        comment: 'Current session ID using this device',
      },
      metadata: {
        type: Sequelize.TEXT,
        allowNull: true,
        comment: 'JSON metadata for extra configuration',
      },
      created_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.NOW,
        allowNull: false,
      },
      updated_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.NOW,
        allowNull: false,
      },
    });

    // Add indexes for cloud_devices
    await addIndexIfNotExists(queryInterface, 'cloud_devices', ['cloud_provider_id'], {
      name: 'idx_cloud_devices_cloud_provider_id',
    });
    await addIndexIfNotExists(queryInterface, 'cloud_devices', ['platform'], {
      name: 'idx_cloud_devices_platform',
    });
    await addIndexIfNotExists(queryInterface, 'cloud_devices', ['platform_version'], {
      name: 'idx_cloud_devices_platform_version',
    });
    await addIndexIfNotExists(queryInterface, 'cloud_devices', ['is_active'], {
      name: 'idx_cloud_devices_is_active',
    });

    // Add cloud session columns to sessions table
    await addColumnIfNotExists(queryInterface, 'sessions', 'cloud_provider_id', {
      type: Sequelize.UUID,
      allowNull: true,
      references: {
        model: 'cloud_providers',
        key: 'id',
      },
      onUpdate: 'CASCADE',
      onDelete: 'SET NULL',
      comment: 'Cloud provider for this session (null for local sessions)',
    });

    await addColumnIfNotExists(queryInterface, 'sessions', 'cloud_device_id', {
      type: Sequelize.UUID,
      allowNull: true,
      references: {
        model: 'cloud_devices',
        key: 'id',
      },
      onUpdate: 'CASCADE',
      onDelete: 'SET NULL',
      comment: 'Cloud device for this session (null for local sessions)',
    });

    await addColumnIfNotExists(queryInterface, 'sessions', 'cloud_session_id', {
      type: Sequelize.STRING(255),
      allowNull: true,
      comment: 'Session ID from the cloud provider',
    });

    // Make node_id nullable for cloud sessions (cloud sessions don't have a local node)
    await queryInterface.changeColumn('sessions', 'node_id', {
      type: Sequelize.UUID,
      allowNull: true,
      references: {
        model: 'nodes',
        key: 'id',
      },
      onUpdate: 'CASCADE',
      onDelete: 'CASCADE',
    });

    // Add index for cloud sessions
    await addIndexIfNotExists(queryInterface, 'sessions', ['cloud_provider_id'], {
      name: 'idx_sessions_cloud_provider_id',
    });
  },

  async down(queryInterface, Sequelize) {
    // Remove indexes first
    try {
      await queryInterface.removeIndex('sessions', 'idx_sessions_cloud_provider_id');
    } catch (error) {
      // Index might not exist
    }

    // Remove columns from sessions table
    try {
      await queryInterface.removeColumn('sessions', 'cloud_session_id');
    } catch (error) {
      // Column might not exist
    }
    try {
      await queryInterface.removeColumn('sessions', 'cloud_device_id');
    } catch (error) {
      // Column might not exist
    }
    try {
      await queryInterface.removeColumn('sessions', 'cloud_provider_id');
    } catch (error) {
      // Column might not exist
    }

    // Drop tables in reverse order (due to foreign key constraints)
    await queryInterface.dropTable('cloud_devices');
    await queryInterface.dropTable('cloud_providers');
  },
};
