#!/usr/bin/env node
/* eslint-disable */
/**
 * Script to get test files for a specific batch in CI using Jest's --listTests.
 * Generates a Jest filter module for batch-specific test execution.
 *
 * Usage:
 *   node scripts/get-test-batch.js <batch-index> <total-batches> --write-config --config=jest-filter-batch.js
 *
 * Example:
 *   node scripts/get-test-batch.js 1 5 --write-config --config=jest-filter-batch-1.js
 *
 * Features:
 * - Uses Jest's --listTests to get the exact list of tests Jest will discover
 * - Splits tests evenly across batches for parallel execution
 * - Generates Jest filter modules (for use with --filter option)
 * - Automatically picks up new test files without configuration changes
 */

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

// Parse CLI args
if (process.argv.length < 4) {
  console.error('Usage: node scripts/get-test-batch.js <batch-index> <total-batches> --write-config --config=jest-filter-batch.js');
  process.exit(1);
}

const batchIndex = parseInt(process.argv[2], 10);
const totalBatches = parseInt(process.argv[3], 10);

let writeConfig = false;
let configPath = 'jest-filter-batch.js';

// Handle optional flags
for (let i = 4; i < process.argv.length; i++) {
  const arg = process.argv[i];
  if (arg === '--write-config') {
    writeConfig = true;
  } else if (arg.startsWith('--config=')) {
    configPath = arg.substring('--config='.length);
  }
}

if (isNaN(batchIndex) || isNaN(totalBatches) || batchIndex < 1 || batchIndex > totalBatches) {
  console.error(`Invalid batch index: ${batchIndex}. Must be between 1 and ${totalBatches}`);
  process.exit(1);
}

// Get all test files using Jest's --listTests
console.error('Discovering test files using Jest...');
let testFiles;
try {
  // Try with yarn first (for CI), fall back to npx if yarn has issues
  let output;
  try {
    output = execSync('yarn --silent jest --listTests --config test/unit/jest.config.js', {
      cwd: path.join(__dirname, '..'),
      encoding: 'utf8',
      stdio: ['pipe', 'pipe', 'pipe']
    });
  } catch (yarnError) {
    // Fall back to using node_modules/.bin/jest directly
    output = execSync('./node_modules/.bin/jest --listTests --config test/unit/jest.config.js', {
      cwd: path.join(__dirname, '..'),
      encoding: 'utf8',
      stdio: ['pipe', 'pipe', 'pipe']
    });
  }
  
  testFiles = output.trim().split('\n').filter(line => line.trim().length > 0);
  console.error(`Found ${testFiles.length} test files`);
} catch (error) {
  console.error('Error running Jest --listTests:', error.message);
  process.exit(1);
}

if (testFiles.length === 0) {
  console.error('No test files found');
  process.exit(2);
}

// Sort for consistent distribution
testFiles.sort();

// Separate snapshot tests from regular tests for better distribution
const snapshotTests = testFiles.filter(f => f.includes('.snap') || f.includes('__snapshots__'));
const regularTests = testFiles.filter(f => !f.includes('.snap') && !f.includes('__snapshots__'));

console.error(`Snapshot tests: ${snapshotTests.length}, Regular tests: ${regularTests.length}`);

// Distribute tests using round-robin to spread snapshot tests evenly across batches
// This prevents slow snapshot tests from clustering in later batches
const batches = Array.from({ length: totalBatches }, () => []);

// Distribute snapshot tests round-robin
snapshotTests.forEach((test, index) => {
  const batchIdx = index % totalBatches;
  batches[batchIdx].push(test);
});

// Distribute regular tests round-robin
regularTests.forEach((test, index) => {
  const batchIdx = index % totalBatches;
  batches[batchIdx].push(test);
});

const batchFiles = batches[batchIndex - 1];

if (batchFiles.length === 0) {
  console.error(`No test files found for batch ${batchIndex} (of ${totalBatches})`);
  process.exit(2);
}

const snapshotCount = batchFiles.filter(f => f.includes('.snap') || f.includes('__snapshots__')).length;
console.error(`Batch ${batchIndex}: ${batchFiles.length} files (${snapshotCount} snapshot tests)`);

const visualBuilderDir = path.join(__dirname, '..');

if (!writeConfig) {
  // Convert absolute paths to relative paths for output
  const relativeBatchFiles = batchFiles.map(f => path.relative(visualBuilderDir, f));
  console.log(relativeBatchFiles.join(' '));
  process.exit(0);
}

// Resolve config path
if (!path.isAbsolute(configPath)) {
  configPath = path.join(visualBuilderDir, configPath);
}

// Generate Jest filter module using absolute paths for reliable matching
const filterModuleContent = `// Auto-generated Jest filter for batch ${batchIndex} of ${totalBatches}
// Generated by: scripts/get-test-batch.js
// Total test files in this batch: ${batchFiles.length}

// Test files for batch ${batchIndex} (absolute paths)
const batchFiles = new Set(${JSON.stringify(batchFiles, null, 2)});

/**
 * Jest 27.4.7 filter function - receives list of test paths and returns filtered list
 * @param {Array<string>} testPaths - Array of absolute test file paths discovered by Jest
 * @returns {Promise<{ filtered: Array<{ test: string }> }>} - Object with filtered array for Jest 27.x
 */
module.exports = async (testPaths) => {
  console.error('=== Filter Debug Info ===');
  console.error('Total test paths received:', testPaths.length);
  console.error('Batch files in set:', batchFiles.size);
  
  if (testPaths.length > 0) {
    console.error('First test path from Jest:', testPaths[0]);
    console.error('First batch file in set:', Array.from(batchFiles)[0]);
    console.error('Paths match:', batchFiles.has(testPaths[0]));
  }
  
  // Filter by absolute path matching for reliability
  const filteredPaths = testPaths.filter((testPath) => batchFiles.has(testPath));
  
  console.error(\`Batch ${batchIndex}: Filtered \${filteredPaths.length} of \${testPaths.length} test files\`);
  
  if (filteredPaths.length === 0 && testPaths.length > 0) {
    console.error('WARNING: No tests matched! Showing sample comparison:');
    console.error('Sample Jest path:', testPaths[0]);
    console.error('Sample batch path:', Array.from(batchFiles)[0]);
  }
  
  if (filteredPaths.length > 0) {
    console.error('Sample filtered paths (first 3):');
    filteredPaths.slice(0, 3).forEach(p => console.error('  -', p));
  }
  
  // Jest 27.4.7 expects: { filtered: Array<{ test: string }> }
  const filtered = filteredPaths.map(testPath => ({ test: testPath }));
  
  console.error('Returning object with filtered array of length:', filtered.length);
  console.error('Return format: { filtered: Array<{ test: string }> }');
  
  return { filtered };
};
`;

try {
  fs.writeFileSync(configPath, filterModuleContent, 'utf8');
  console.log(configPath);
} catch (error) {
  console.error(`Failed to write filter module to: ${configPath}`);
  console.error(error.message);
  process.exit(4);
}
