#!/usr/bin/env node
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-var-requires */

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

const SUPPORTED_COMPONENTS = [
  'Input',
  'Button',
  'Badge',
  'Card',
  'InfoPanel',
  'NotificationItem',
  'NotificationsWrapper',
];

// Color utilities for better console output
const COLOURS = {
  green: '\x1b[32m',
  blue: '\x1b[34m',
  yellow: '\x1b[33m',
  red: '\x1b[31m',
  reset: '\x1b[0m',
  bold: '\x1b[1m',
};

const BATCH_SIZE = 500;

// Parse command line arguments
function parseArguments() {
  const args = process.argv.slice(2);
  const ignoreFoldersIndex = args.indexOf('--ignoreFolders');
  
  if (ignoreFoldersIndex !== -1 && ignoreFoldersIndex < args.length - 1) {
    // Get all arguments after --ignoreFolders until the next flag or end
    const foldersToIgnore = [];
    for (let i = ignoreFoldersIndex + 1; i < args.length; i++) {
      if (args[i].startsWith('--')) {
        break;
      }
      foldersToIgnore.push(args[i]);
    }
    return foldersToIgnore;
  }
  
  return [];
}

const FOLDERS_TO_IGNORE = parseArguments();

function shouldIgnore(input) {
  // If no folders to ignore are specified, don't ignore anything
  if (FOLDERS_TO_IGNORE.length === 0) {
    return false;
  }
  
  return FOLDERS_TO_IGNORE.some(
    pattern =>
      input === pattern ||
      input.startsWith(pattern) ||
      input.includes(`/${pattern}/`) ||
      input.includes(`\\${pattern}\\`)
  );
}

const FILE_EXTENSIONS_TO_SEARCH = ['.tsx', '.jsx'];
function shouldProcessFileExtension(fileName) {
  return FILE_EXTENSIONS_TO_SEARCH.some(ext => fileName.endsWith(ext));
}

function log(message, color = 'reset') {
  console.log(`${COLOURS[color]}${message}${COLOURS.reset}`);
}

async function promptComponentSelection() {
  return new Promise((resolve) => {
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    });

    log('\n🎯 Select a component to migrate from fictoan-react to @setu/components:', 'bold');
    log('');
    
    SUPPORTED_COMPONENTS.forEach((component, index) => {
      log(`${index + 1} - ${component}`, 'blue');
    });
    
    log(`${SUPPORTED_COMPONENTS.length + 1} - All components`, 'green');
    log('');

    rl.question('Enter your choice (number): ', (answer) => {
      rl.close();
      
      const choice = parseInt(answer.trim());
      
      if (choice >= 1 && choice <= SUPPORTED_COMPONENTS.length) {
        const selectedComponent = SUPPORTED_COMPONENTS[choice - 1];
        log(`\n✅ Selected: ${selectedComponent}`, 'green');
        resolve([selectedComponent]);
      } else if (choice === SUPPORTED_COMPONENTS.length + 1) {
        log('\n✅ Selected: All components', 'green');
        resolve(SUPPORTED_COMPONENTS);
      } else {
        log('\n❌ Invalid choice. Exiting...', 'red');
        process.exit(1);
      }
    });
  });
}

function findFiles() {
  const fs = require('fs');
  const path = require('path');

  function findFilesRecursively(dir, files = []) {
    try {
      const items = fs.readdirSync(dir, { withFileTypes: true });
      for (const item of items) {
        const fullPath = path.join(dir, item.name);

        // Skip ignored directories
        if (item.isDirectory() && shouldIgnore(item.name)) {
          continue;
        }

        if (item.isDirectory()) {
          findFilesRecursively(fullPath, files);
        } else if (
          item.isFile() &&
          shouldProcessFileExtension(item.name) &&
          !shouldIgnore(fullPath)
        ) {
          files.push(fullPath);
        }
      }
    } catch (error) {
      console.log(`⚠️ Skipping directory ${dir}: ${error.message}`);
    }
    return files;
  }

  try {
    return findFilesRecursively(process.cwd(), []);
  } catch {
    log(
      "❌ Error finding files. Make sure you're in a valid project directory.",
      'red'
    );
    return [];
  }
}
function runTransformation(files, selectedComponents) {
  try {
    if (files.length === 0) {
      log('📭 No files found to transform', 'yellow');
      return;
    }

    log(`🔧 Found ${files.length} files to check...`, 'blue');
    log(`🎯 Migrating components: ${selectedComponents.join(', ')}`, 'blue');

    const transformerPath = path.join(__dirname, 'transformer.js');

    // Separate files by type
    const tsxFiles = files.filter(file => file.endsWith('.tsx'));
    const jsxFiles = files.filter(file => file.endsWith('.jsx'));

    log(`📋 File breakdown: ${tsxFiles.length} TSX files, ${jsxFiles.length} JSX files`, 'blue');

    let modifiedCount = 0;
    let unchangedCount = 0;
    const startTime = Date.now();

    // Process TSX files with tsx parser
    if (tsxFiles.length > 0) {
      log(`🔧 Processing ${tsxFiles.length} TSX files...`, 'blue');
      const { modified, unchanged } = processBatches(tsxFiles, selectedComponents, transformerPath, BATCH_SIZE, 'tsx');
      modifiedCount += modified;
      unchangedCount += unchanged;
    }

    // Process JSX files with babel parser
    if (jsxFiles.length > 0) {
      log(`🔧 Processing ${jsxFiles.length} JSX files...`, 'blue');
      const { modified, unchanged } = processBatches(jsxFiles, selectedComponents, transformerPath, BATCH_SIZE, 'babel');
      modifiedCount += modified;
      unchangedCount += unchanged;
    }

    const endTime = Date.now();
    const totalDuration = endTime - startTime;
    const avgTimePerFile = files.length > 0 ? Math.round(totalDuration / files.length) : 0;

    log('\n🎉 Migration completed!', 'green');
    log(`📈 Performance Summary:`, 'bold');
    log(`  • Total files processed: ${files.length}`, 'reset');
    log(`  • Files modified: ${modifiedCount}`, 'green');
    log(`  • Files unchanged: ${unchangedCount}`, 'blue');
    log(
      `  • Total time: ${totalDuration}ms (${(totalDuration / 1000).toFixed(1)}s)`,
      'reset'
    );
    log(`  • Average time per file: ${avgTimePerFile}ms`, 'reset');
    log(`  • Batch size: ${BATCH_SIZE}`, 'reset');
    log(`  • Processing method: Separated by file type`, 'reset');

    log('\n📝 Please review the changes and test your application.', 'blue');
    log('\n📋 Summary:', 'bold');
    log('  • Migrated fictoan-react imports to @setu/components', 'reset');
    log(
      `  • Migrated components: ${selectedComponents.join(', ')}`,
      'reset'
    );
    log('  • Kept non-migrated components with fictoan-react', 'reset');

    log('\n🔗 Next steps:', 'bold');
    log('  1. Review the changes in your code', 'reset');
    log('  2. Test your application to ensure everything works', 'reset');
    log('  3. Install @setu/components if not already installed:', 'reset');
    log('     npm install @setu/components', 'blue');
  } catch (error) {
    log(`❌ Error during transformation: ${error.message}`, 'red');
    process.exit(1);
  }
}

function processBatches(files, selectedComponents, transformerPath, batchSize, parser) {
  let modifiedCount = 0;
  let unchangedCount = 0;

  // Process files in batches
  for (let i = 0; i < files.length; i += batchSize) {
    const batch = files.slice(i, i + batchSize);
    const batchNumber = Math.floor(i / batchSize) + 1;
    const totalBatches = Math.ceil(files.length / batchSize);

    log(
      `📦 Processing ${parser.toUpperCase()} batch ${batchNumber}/${totalBatches} (${batch.length} files)`,
      'blue'
    );

    // Create file list for this batch
    const batchFileArgs = batch.map(f => `"${f}"`).join(' ');

    // Build jscodeshift command for batch
    const jscodeshiftCmd = 'npx jscodeshift';
    const componentsArg = `--selectedComponents="${selectedComponents.join(',')}"`;
    const command = `${jscodeshiftCmd} -t "${transformerPath}" --parser=${parser} ${componentsArg} --ignore-pattern="**/*.test.*" --ignore-pattern="**/*.spec.*" ${batchFileArgs}`;

    try {
      const result = execSync(command, {
        stdio: ['inherit', 'pipe', 'pipe'],
        encoding: 'utf8',
      });

      // Parse results to count modifications
      const lines = result.split('\n');
      let batchModified = 0;
      let batchUnchanged = 0;
      
      for (const line of lines) {
        // Look for patterns like "1 ok, 2 unmodified, 0 skipped, 0 errors."
        if (line.match(/\d+\s+ok/)) {
          const okMatch = line.match(/(\d+)\s+ok/);
          if (okMatch) {
            const count = parseInt(okMatch[1]);
            batchModified += count;
          }
        }
        if (line.match(/\d+\s+unmodified/)) {
          const unmodifiedMatch = line.match(/(\d+)\s+unmodified/);
          if (unmodifiedMatch) {
            const count = parseInt(unmodifiedMatch[1]);
            batchUnchanged += count;
          }
        }
      }
      
      modifiedCount += batchModified;
      unchangedCount += batchUnchanged;
      
    } catch (batchError) {
      log(
        `⚠️  Warning processing ${parser.toUpperCase()} batch ${batchNumber}: ${batchError.message}`,
        'yellow'
      );
      unchangedCount += batch.length;
    }
  }

  return { modified: modifiedCount, unchanged: unchangedCount };
}

async function main() {
  log('🚀 Starting Fictoan to Setu Components migration...', 'bold');
  
  // Show which folders are being ignored
  if (FOLDERS_TO_IGNORE.length > 0) {
    log(`📂 Ignoring folders: ${FOLDERS_TO_IGNORE.join(', ')}`, 'blue');
  } else {
    log('📂 No folders will be ignored (processing all files)', 'blue');
  }

  const files = findFiles();

  if (files.length === 0) {
    log('📭 No React files found in the current directory', 'yellow');
    log(
      "💡 Make sure you're running this in a React project directory",
      'blue'
    );
    process.exit(0);
  }

  log(`📋 Found ${files.length} files to analyze`, 'green');

  // Show some of the files that will be processed
  if (files.length > 0) {
    log('\n📁 Files to be processed:', 'blue');
    files.slice(0, 10).forEach(file => {
      log(`   ${file}`, 'reset');
    });
    if (files.length > 10) {
      log(`   ... and ${files.length - 10} more files`, 'reset');
    }
  }

  // Get user's component selection
  const selectedComponents = await promptComponentSelection();

  runTransformation(files, selectedComponents);
}

if (require.main === module) {
  main();
}

module.exports = {
  main,
  findFiles,
  runTransformation,
  promptComponentSelection,
};