import { Command } from 'commander';
import path from 'path';
import fs from 'fs';
import express from 'express';
import { spawn } from 'child_process';
import { generateGraphData } from '../utils/dependency-analyzer';
import { createFileSystem } from '../utils/file-operations';
import { logger } from '../utils/logger';

export interface VisualizeOptions {
  port?: number;
  output?: string;
  format?: 'json' | 'console' | 'app';
  projectRoot?: string;
  open?: boolean;
}

export const createVisualizeCommand = (): Command => {
  const command = new Command('visualize');
  
  command
    .description('Visualize domain dependencies in an interactive React app')
    .option('-p, --port <port>', 'Port for the web server', '3000')
    .option('-o, --output <path>', 'Output path for graph data JSON')
    .option('-f, --format <format>', 'Output format (json|console|app)', 'app')
    .option('-r, --project-root <path>', 'Project root directory', process.cwd())
    .option('--no-open', 'Do not automatically open browser')
    .action(async (options: VisualizeOptions) => {
      try {
        await executeVisualize(options);
      } catch (error) {
        logger.error(`Failed to run visualize: ${error instanceof Error ? error.message : 'Unknown error'}`);
        process.exit(1);
      }
    });
  
  return command;
};

const displayConsoleVisualization = (graphData: any): void => {
  console.log('\n🏗️  RUCH Domain Visualization\n');
  console.log('═'.repeat(50));
  
  // Stats
  console.log(`📊 Statistics:`);
  console.log(`   • Domains: ${graphData.stats.totalDomains}`);
  console.log(`   • Dependencies: ${graphData.stats.totalDependencies}`);
  console.log(`   • Circular Dependencies: ${graphData.stats.circularDependencyCount}`);
  console.log('');
  
  // Domains
  console.log('📁 Domains:');
  graphData.nodes.forEach((node: any) => {
    const typeEmoji = node.type === 'core' ? '🔧' : node.type === 'shared' ? '🔗' : '⚡';
    console.log(`   ${typeEmoji} ${node.name} (${node.fileCount} files)`);
    
    if (node.dependencies.length > 0) {
      console.log(`      Dependencies: ${node.dependencies.join(', ')}`);
    }
  });
  
  // Circular dependencies
  if (graphData.circularDependencies.length > 0) {
    console.log('\n⚠️  Circular Dependencies:');
    graphData.circularDependencies.forEach((cycle: string[], index: number) => {
      console.log(`   ${index + 1}. ${cycle.join(' → ')} → ${cycle[0]}`);
    });
  }
  
  console.log('\n' + '═'.repeat(50));
  console.log('💡 Tip: Use --format json to export data or --format app to start the interactive app');
};

const openBrowser = (url: string): void => {
  const start = process.platform === 'darwin' ? 'open' : 
                process.platform === 'win32' ? 'start' : 'xdg-open';
  
  spawn(start, [url], { detached: true, stdio: 'ignore' });
};

const createExpressServer = (graphData: any, port: number): Promise<void> => {
  return new Promise((resolve, reject) => {
    const app = express();
    
    // Get the path to the built React app
    const cliPath = path.dirname(require.resolve('../../package.json'));
    const appDistPath = path.join(cliPath, 'src', 'visualizer', 'app', 'dist');
    
    // API endpoint for graph data
    app.get('/api/graph', (req, res) => {
      res.json(graphData);
    });
    
    // Serve static React app
    app.use(express.static(appDistPath));
    
    // Fallback to index.html for SPA routing
    app.get('*', (req, res) => {
      res.sendFile(path.join(appDistPath, 'index.html'));
    });
    
    const server = app.listen(port, () => {
      resolve();
    });
    
    server.on('error', (error) => {
      reject(error);
    });
    
    // Handle graceful shutdown
    process.on('SIGINT', () => {
      logger.info('Shutting down visualization server...');
      server.close(() => {
        process.exit(0);
      });
    });
  });
};

const buildReactApp = async (): Promise<void> => {
  return new Promise((resolve, reject) => {
    const cliPath = path.dirname(require.resolve('../../package.json'));
    const appPath = path.join(cliPath, 'src', 'visualizer', 'app');
    
    logger.info('📦 Building React app...');
    
    const buildProcess = spawn('npm', ['run', 'build'], {
      cwd: appPath,
      stdio: 'pipe',
      shell: true
    });
    
    buildProcess.stdout?.on('data', (data) => {
      // Optionally log build output
    });
    
    buildProcess.stderr?.on('data', (data) => {
      console.error(data.toString());
    });
    
    buildProcess.on('close', (code) => {
      if (code === 0) {
        logger.success('✅ React app built successfully');
        resolve();
      } else {
        reject(new Error(`Build process exited with code ${code}`));
      }
    });
  });
};

export const executeVisualize = async (options: VisualizeOptions): Promise<void> => {
  const projectRoot = options.projectRoot || process.cwd();
  const port = parseInt(options.port?.toString() || '3000');
  const shouldOpen = options.open !== false;
  
  logger.info('🔍 Analyzing domain dependencies...');
  
  // Generate graph data from user's project
  const fileSystem = createFileSystem();
  const graphData = await generateGraphData(projectRoot, fileSystem);
  
  if (graphData.nodes.length === 0) {
    logger.warning('No domains found in src/domains/. Make sure you have domains created.');
    return;
  }
  
  logger.success(`Found ${graphData.stats.totalDomains} domains with ${graphData.stats.totalDependencies} dependencies`);
  
  if (graphData.stats.circularDependencyCount > 0) {
    logger.warning(`⚠️  Found ${graphData.stats.circularDependencyCount} circular dependencies`);
  }
  
  // Handle different output formats
  if (options.format === 'json' || options.output) {
    const outputPath = options.output || path.join(projectRoot, 'graph-data.json');
    await fs.promises.writeFile(outputPath, JSON.stringify(graphData, null, 2));
    logger.success(`Graph data saved to: ${outputPath}`);
    
    if (options.format === 'json') {
      return; // Only output JSON, don't start server
    }
  }
  
  if (options.format === 'console') {
    displayConsoleVisualization(graphData);
    return;
  }
  
  // Default behavior: start React app with Express server
  try {
    // Build the React app first
    await buildReactApp();
    
    logger.info('🚀 Starting visualization server...');
    
    // Start Express server
    await createExpressServer(graphData, port);
    
    const url = `http://localhost:${port}`;
    logger.success(`🎯 Visualization ready at: ${url}`);
    
    if (shouldOpen) {
      setTimeout(() => openBrowser(url), 1000); // Small delay to ensure server is ready
    }
    
    // Keep the process alive
    logger.info('Press Ctrl+C to stop the server');
    
  } catch (error) {
    logger.error(`Failed to start server: ${error instanceof Error ? error.message : 'Unknown error'}`);
    process.exit(1);
  }
}; 