#!/usr/bin/env node

try {
  // Direct implementation of comment removal
  const fs = require('fs');
  const path = require('path');
  const { Command } = require('commander');
  const chalk = require('chalk');
  const ora = require('ora');
  const fg = require('fast-glob');

  // Ensure ora is properly imported
  const createSpinner = ora.default || ora;

  // Function to remove comments from JavaScript code
  function removeJavaScriptComments(code) {
    let result = code;

    try {
      // First, preserve strings and regexes to avoid modifying comments inside them
      const preservedItems = [];
      let preservedCount = 0;

      // Temporarily replace strings and regexes with placeholders
      result = result.replace(
        /(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1|\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\/(?:[gimuy]+\b)?/g,
        (match) => {
          const placeholder = `__PRESERVED_ITEM_${preservedCount}__`;
          preservedItems[preservedCount] = match;
          preservedCount++;
          return placeholder;
        }
      );

      // Remove JSX comments
      result = result.replace(/\{\/\*[\s\S]*?\*\/\}/g, '');

      // Remove multi-line comments
      result = result.replace(/\/\*[\s\S]*?\*\//g, '');

      // Remove single-line comments
      // Handle comments at start of line
      result = result.replace(/^[ \t]*\/\/.*$/gm, '');
      // Handle comments after code (but not in URLs)
      result = result.replace(/([^:/])\/\/.*$/gm, '$1');

      // Restore preserved strings and regexes
      for (let i = 0; i < preservedCount; i++) {
        const placeholder = `__PRESERVED_ITEM_${i}__`;
        const regex = new RegExp(placeholder, 'g');
        result = result.replace(regex, () => preservedItems[i]);
      }

      // Remove empty lines
      // Remove lines that contain only whitespace
      result = result.replace(/^\s*[\r\n]/gm, '');
      // Remove consecutive empty lines (preserving indentation)
      result = result.replace(/\n(\s*)\n(\s*)\n/g, '\n$2\n');
      // Remove empty lines at the beginning and end of the file
      result = result.replace(/^(\s*\n)+/, '');
      result = result.replace(/(\n\s*)+$/, '');

      return result.trim();
    } catch (error) {
      console.error(`JavaScript comment removal failed: ${error.message}`);
      return code;
    }
  }

  // Create the clean command
  const command = new Command('devtools-clean');

  command
    .description('Remove comments from code files')
    .argument('<patterns...>', 'File patterns to clean (e.g., "src/**/*.js")')
    .option('--single-line', 'Remove single-line comments', true)
    .option('--multi-line', 'Remove multi-line comments', true)
    .option('--jsx', 'Remove JSX comments', true)
    .option('--empty-lines', 'Remove empty lines', true)
    .option('--ignore <pattern>', 'Files to ignore (comma-separated)', value => value.split(',').map(item => item.trim()))
    .option('--write', 'Write changes to files', true)
    .option('--silent', 'Suppress output', false)
    .action(async (patterns, options) => {
      const silent = options.silent;

      try {
        // Start spinner
        const spinner = createSpinner({
          text: 'Removing comments...',
          color: 'cyan',
          spinner: 'dots'
        }).start();

        // Process each file
        let results = [];

        // Normalize patterns for Windows paths
        const normalizedPatterns = patterns.map(pattern => {
          // Convert Windows backslashes to forward slashes for glob
          return pattern.replace(/\\/g, '/');
        });

        // Default ignore patterns
        const defaultIgnore = [
          '**/node_modules/**',
          '**/dist/**',
          '**/build/**',
          '**/.git/**',
          '**/package-lock.json',
          '**/yarn.lock',
          '**/*.min.js',
          '**/*.min.css',
          '**/*.bundle.js'
        ];

        // Combine with user-provided ignore patterns
        const ignorePatterns = options.ignore
          ? [...defaultIgnore, ...options.ignore]
          : defaultIgnore;

        // Find all files matching the patterns
        const files = await fg(normalizedPatterns, {
          ignore: ignorePatterns,
          onlyFiles: true,
          absolute: true, // Use absolute paths to handle Windows paths better
          followSymbolicLinks: false // Don't follow symlinks to avoid circular references
        });

        for (const file of files) {
          try {
            // Read the file
            const content = fs.readFileSync(file, 'utf8');
            const originalSize = content.length;

            // Process the file based on extension
            const ext = path.extname(file).toLowerCase();
            let newContent;

            // JavaScript/TypeScript family
            if (['.js', '.jsx', '.ts', '.tsx', '.json', '.mjs', '.cjs', '.vue', '.svelte', '.astro'].includes(ext)) {
              newContent = removeJavaScriptComments(content);
            }
            // HTML/XML family
            else if (['.html', '.htm', '.xml', '.svg', '.xhtml', '.jsp', '.asp', '.aspx', '.cshtml', '.razor', '.ejs', '.hbs', '.handlebars', '.pug', '.jade'].includes(ext)) {
              try {
                // For HTML files, remove HTML comments
                newContent = content.replace(/<!--[\s\S]*?-->/g, '');

                // Also process script and style tags for JS and CSS comments
                newContent = newContent.replace(/(<script\b[^>]*>)([\s\S]*?)(<\/script>)/gi, (match, openTag, scriptContent, closeTag) => {
                  return openTag + removeJavaScriptComments(scriptContent) + closeTag;
                });

                newContent = newContent.replace(/(<style\b[^>]*>)([\s\S]*?)(<\/style>)/gi, (match, openTag, styleContent, closeTag) => {
                  // Remove CSS comments
                  let cleanedStyle = styleContent.replace(/\/\*[\s\S]*?\*\//g, '');
                  // Remove empty lines
                  cleanedStyle = cleanedStyle.replace(/^\s*[\r\n]/gm, '');
                  cleanedStyle = cleanedStyle.replace(/\n\s*\n/g, '\n');
                  return openTag + cleanedStyle + closeTag;
                });
              } catch (error) {
                console.error(`Error processing HTML file ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // CSS family
            else if (['.css', '.scss', '.sass', '.less', '.styl', '.stylus', '.pcss', '.postcss'].includes(ext)) {
              try {
                // For CSS files, remove CSS comments
                newContent = content.replace(/\/\*[\s\S]*?\*\//g, '');
                // Remove empty lines
                newContent = newContent.replace(/^\s*[\r\n]/gm, '');
                newContent = newContent.replace(/\n\s*\n/g, '\n');
              } catch (error) {
                console.error(`Error processing CSS file ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // C-style languages (C, C++, C#, Java, etc.)
            else if (['.c', '.h', '.cpp', '.hpp', '.cc', '.cxx', '.c++', '.cs', '.java', '.go', '.swift', '.kt', '.scala', '.php', '.php5', '.phtml', '.inc'].includes(ext)) {
              try {
                // C-style comments are similar to JavaScript
                newContent = removeJavaScriptComments(content);
              } catch (error) {
                console.error(`Error processing C-style file ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // Python, Ruby, Perl, etc.
            else if (['.py', '.pyw', '.rb', '.pl', '.pm', '.r', '.jl'].includes(ext)) {
              try {
                // Preserve strings
                const preservedItems = [];
                let preservedCount = 0;

                // Temporarily replace strings with placeholders
                let result = content.replace(
                  /(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1|"""[\s\S]*?"""|'''[\s\S]*?'''/g,
                  (match) => {
                    const placeholder = `__PRESERVED_ITEM_${preservedCount}__`;
                    preservedItems[preservedCount] = match;
                    preservedCount++;
                    return placeholder;
                  }
                );

                // Remove single-line comments (# in Python, Ruby, etc.)
                result = result.replace(/^[ \t]*#.*$/gm, '');
                result = result.replace(/([^\\])#.*$/gm, '$1');

                // Restore preserved strings
                for (let i = 0; i < preservedCount; i++) {
                  const placeholder = `__PRESERVED_ITEM_${i}__`;
                  const regex = new RegExp(placeholder, 'g');
                  result = result.replace(regex, () => preservedItems[i]);
                }

                // Remove empty lines
                result = result.replace(/^\s*[\r\n]/gm, '');
                result = result.replace(/\n\s*\n/g, '\n');

                newContent = result;
              } catch (error) {
                console.error(`Error processing Python/Ruby file ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // Shell scripts
            else if (['.sh', '.bash', '.zsh', '.fish', '.ksh', '.bat', '.cmd', '.ps1'].includes(ext)) {
              try {
                // Preserve strings
                const preservedItems = [];
                let preservedCount = 0;

                // Temporarily replace strings with placeholders
                let result = content.replace(
                  /(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/g,
                  (match) => {
                    const placeholder = `__PRESERVED_ITEM_${preservedCount}__`;
                    preservedItems[preservedCount] = match;
                    preservedCount++;
                    return placeholder;
                  }
                );

                // Remove single-line comments (# in shell scripts)
                result = result.replace(/^[ \t]*#.*$/gm, '');
                result = result.replace(/([^\\])#.*$/gm, '$1');

                // For batch files, remove REM comments
                if (['.bat', '.cmd'].includes(ext)) {
                  result = result.replace(/^[ \t]*REM.*$/gim, '');
                }

                // For PowerShell, remove # and <# #> comments
                if (['.ps1'].includes(ext)) {
                  result = result.replace(/^[ \t]*#.*$/gm, '');
                  result = result.replace(/<#[\s\S]*?#>/g, '');
                }

                // Restore preserved strings
                for (let i = 0; i < preservedCount; i++) {
                  const placeholder = `__PRESERVED_ITEM_${i}__`;
                  const regex = new RegExp(placeholder, 'g');
                  result = result.replace(regex, () => preservedItems[i]);
                }

                // Remove empty lines
                result = result.replace(/^\s*[\r\n]/gm, '');
                result = result.replace(/\n\s*\n/g, '\n');

                newContent = result;
              } catch (error) {
                console.error(`Error processing shell script ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // SQL
            else if (['.sql', '.mysql', '.pgsql', '.sqlite', '.plsql'].includes(ext)) {
              try {
                // Preserve strings
                const preservedItems = [];
                let preservedCount = 0;

                // Temporarily replace strings with placeholders
                let result = content.replace(
                  /(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/g,
                  (match) => {
                    const placeholder = `__PRESERVED_ITEM_${preservedCount}__`;
                    preservedItems[preservedCount] = match;
                    preservedCount++;
                    return placeholder;
                  }
                );

                // Remove single-line comments (-- in SQL)
                result = result.replace(/^[ \t]*--.*$/gm, '');
                result = result.replace(/([^:-])--.*$/gm, '$1');

                // Remove multi-line comments (/* */ in SQL)
                result = result.replace(/\/\*[\s\S]*?\*\//g, '');

                // Restore preserved strings
                for (let i = 0; i < preservedCount; i++) {
                  const placeholder = `__PRESERVED_ITEM_${i}__`;
                  const regex = new RegExp(placeholder, 'g');
                  result = result.replace(regex, () => preservedItems[i]);
                }

                // Remove empty lines
                result = result.replace(/^\s*[\r\n]/gm, '');
                result = result.replace(/\n\s*\n/g, '\n');

                newContent = result;
              } catch (error) {
                console.error(`Error processing SQL file ${file}: ${error.message}`);
                newContent = content; // Keep original content on error
              }
            }
            // Default fallback
            else {
              // Try to detect the language based on content
              if (content.includes('<?php')) {
                // PHP-like syntax
                newContent = removeJavaScriptComments(content);
              } else if (content.includes('<!DOCTYPE') || content.includes('<html')) {
                // HTML-like syntax
                newContent = content.replace(/<!--[\s\S]*?-->/g, '');
              } else if (content.match(/^[ \t]*import\s|^[ \t]*from\s|^[ \t]*export\s|^[ \t]*class\s|^[ \t]*function\s/m)) {
                // JavaScript/TypeScript-like syntax
                newContent = removeJavaScriptComments(content);
              } else if (content.match(/^[ \t]*#include\s|^[ \t]*#define\s|^[ \t]*#ifndef\s/m)) {
                // C/C++-like syntax
                newContent = removeJavaScriptComments(content);
              } else if (content.match(/^[ \t]*def\s|^[ \t]*class\s|^[ \t]*import\s/m) && content.includes('#')) {
                // Python-like syntax
                let result = content;
                // Remove single-line comments (# in Python)
                result = result.replace(/^[ \t]*#.*$/gm, '');
                result = result.replace(/([^\\])#.*$/gm, '$1');
                newContent = result;
              } else {
                // Default to JavaScript comment removal as a fallback
                newContent = removeJavaScriptComments(content);
              }
            }

            const newSize = newContent.length;
            const diffSize = originalSize - newSize;
            const diffPercentage = originalSize > 0 ? (diffSize / originalSize) * 100 : 0;

            // Write the file if requested
            if (options.write) {
              fs.writeFileSync(file, newContent, 'utf8');
            }

            results.push({
              path: file,
              success: true,
              originalSize,
              newSize,
              diffSize,
              diffPercentage
            });
          } catch (error) {
            results.push({
              path: file,
              success: false,
              error: error.message
            });
          }
        }

        // Stop spinner
        spinner.succeed(`Processed ${results.length} files`);

        // Log results
        if (!silent) {
          const successCount = results.filter(r => r.success).length;
          const errorCount = results.length - successCount;

          console.log('\n' + chalk.bold('Results:'));
          console.log(`${chalk.green(`${successCount} files`)} processed successfully`);

          if (errorCount > 0) {
            console.log(`${chalk.red(`${errorCount} files`)} failed to process`);
            console.log('\n' + chalk.bold('Errors:'));
            results
              .filter(r => !r.success)
              .forEach(result => {
                console.log(`  ${chalk.red('✗')} ${result.path}: ${result.error}`);
              });
          }

          // Log size changes
          const successResults = results.filter(r => r.success);
          if (successResults.length > 0) {
            const totalOriginalSize = successResults.reduce((sum, r) => sum + (r.originalSize || 0), 0);
            const totalNewSize = successResults.reduce((sum, r) => sum + (r.newSize || 0), 0);
            const totalDiffSize = totalOriginalSize - totalNewSize;
            const percentChange = totalOriginalSize > 0
              ? (totalDiffSize / totalOriginalSize) * 100
              : 0;

            console.log('\n' + chalk.bold('Size Changes:'));
            console.log(`  Original: ${formatSize(totalOriginalSize)}`);
            console.log(`  New: ${formatSize(totalNewSize)}`);

            if (totalDiffSize > 0) {
              console.log(`  Reduced by: ${chalk.green(formatSize(totalDiffSize))} (${percentChange.toFixed(2)}%)`);
            } else if (totalDiffSize < 0) {
              console.log(`  Increased by: ${chalk.yellow(formatSize(Math.abs(totalDiffSize)))} (${Math.abs(percentChange).toFixed(2)}%)`);
            } else {
              console.log(`  No size change`);
            }
          }

          console.log('\n' + chalk.bold.green(`Comment removal completed.`));
        }

      } catch (error) {
        console.error(chalk.red('✗ ') + error.message);
        process.exit(1);
      }
    });

  // Format size in bytes to a human-readable string
  function formatSize(bytes) {
    if (bytes < 1024) {
      return `${bytes} B`;
    } else if (bytes < 1024 * 1024) {
      return `${(bytes / 1024).toFixed(2)} KB`;
    } else {
      return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
    }
  }

  // Execute the command
  command.parse(process.argv);
} catch (error) {
  console.error('Error loading command:', error.message);
  process.exit(1);
}
