#!/usr/bin/env node

// src/cli.ts - CLI npm pour Web Sentinel
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';
import { glob } from 'glob';

interface WebSentinelConfig {
    apiUrl: string;
    apiKey?: string;
}

interface ScanOptions {
    language?: string[];
    exclude?: string[];
    severityMin?: string;
    output?: string;
    format?: 'json' | 'text' | 'sarif';
}

class WebSentinelCLI {
    private config: WebSentinelConfig;
    
    constructor() {
        this.config = this.loadConfig();
    }

    private loadConfig(): WebSentinelConfig {
        const configPaths = [
            path.join(process.cwd(), '.websentinel.json'),
            path.join(process.env.HOME || '', '.websentinel', 'config.json'),
            path.join(process.cwd(), 'package.json')
        ];

        for (const configPath of configPaths) {
            if (fs.existsSync(configPath)) {
                try {
                    const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
                    
                    // Pour package.json, chercher dans webSentinel
                    if (configPath.endsWith('package.json') && config.webSentinel) {
                        return {
                            apiUrl: config.webSentinel.apiUrl || 'https://api.web-sentinel.com',
                            apiKey: config.webSentinel.apiKey
                        };
                    }
                    
                    return {
                        apiUrl: config.apiUrl || 'https://api.web-sentinel.com',
                        apiKey: config.apiKey
                    };
                } catch (error) {
                    // Ignorer les erreurs de parsing
                }
            }
        }

        return { 
            apiUrl: process.env.WEB_SENTINEL_API_URL || 'https://api.web-sentinel.com',
            apiKey: process.env.WEB_SENTINEL_API_KEY
        };
    }

    async scanFile(filePath: string, options: ScanOptions): Promise<void> {
        if (!this.config.apiKey) {
            console.error(chalk.red('❌ Clé API manquante. Configurez-la avec:'));
            console.error(chalk.yellow('  export WEB_SENTINEL_API_KEY=your_key'));
            console.error(chalk.yellow('  ou créez .websentinel.json'));
            process.exit(1);
        }

        const spinner = ora('Analyse de sécurité en cours...').start();
        
        try {
            const content = fs.readFileSync(filePath, 'utf8');
            const language = this.detectLanguage(filePath);
            
            const payload = {
                source_content: content,
                file_path: filePath,
                language: language,
                api_key: this.config.apiKey,
                options: {
                    severity_min: options.severityMin || 'medium',
                    detailed_report: true
                }
            };

            const response = await axios.post(
                `${this.config.apiUrl}/api/v1/scan-source`,
                payload,
                { 
                    headers: { 'User-Agent': 'Web-Sentinel-NPM/1.0' },
                    timeout: 30000 
                }
            );

            spinner.succeed(`Analyse terminée - ${response.data.findings.length} problèmes détectés`);
            
            this.displayResults(response.data, options);
            
        } catch (error: any) {
            spinner.fail('Erreur lors de l\'analyse');
            
            if (error.response?.status === 401) {
                console.error(chalk.red('❌ Clé API invalide'));
            } else if (error.response?.status === 429) {
                console.error(chalk.yellow('⏱️  Limite de taux atteinte, réessayez plus tard'));
            } else {
                console.error(chalk.red(`❌ Erreur: ${error.message}`));
            }
            process.exit(1);
        }
    }

    async scanDirectory(dirPath: string, options: ScanOptions): Promise<void> {
        const patterns = [
            '**/*.php',
            '**/*.js',
            '**/*.ts', 
            '**/*.py',
            '**/*.java',
            '**/*.cs',
            '**/*.go'
        ];

        const excludePatterns = [
            '**/node_modules/**',
            '**/vendor/**',
            '**/dist/**',
            '**/build/**',
            ...(options.exclude || [])
        ];

        const files: string[] = [];
        
        for (const pattern of patterns) {
            const matches = await glob(pattern, {
                cwd: dirPath,
                ignore: excludePatterns,
                absolute: true
            });
            files.push(...matches);
        }

        if (files.length === 0) {
            console.log(chalk.yellow('⚠️  Aucun fichier source trouvé'));
            return;
        }

        console.log(chalk.blue(`🔍 Analyse de ${files.length} fichiers...`));
        
        const spinner = ora('Scanning files...').start();
        const results: any[] = [];

        for (let i = 0; i < files.length; i++) {
            spinner.text = `Scanning ${path.basename(files[i])} (${i + 1}/${files.length})`;
            
            try {
                const content = fs.readFileSync(files[i], 'utf8');
                const language = this.detectLanguage(files[i]);
                
                const payload = {
                    source_content: content,
                    file_path: files[i],
                    language: language,
                    api_key: this.config.apiKey,
                    options: {
                        severity_min: options.severityMin || 'medium'
                    }
                };

                const response = await axios.post(
                    `${this.config.apiUrl}/api/v1/scan-source`,
                    payload,
                    { timeout: 30000 }
                );

                if (response.data.findings.length > 0) {
                    results.push({
                        file: files[i],
                        findings: response.data.findings
                    });
                }
                
            } catch (error) {
                // Continue avec les autres fichiers
                console.error(chalk.red(`Erreur avec ${files[i]}: ${error}`));
            }
        }

        spinner.succeed(`Analyse terminée`);
        
        this.displayDirectoryResults(results, options);
    }

    private detectLanguage(filePath: string): string {
        const ext = path.extname(filePath).toLowerCase();
        const mapping: {[key: string]: string} = {
            '.php': 'php',
            '.js': 'javascript',
            '.ts': 'javascript', 
            '.py': 'python',
            '.java': 'java',
            '.cs': 'csharp',
            '.go': 'go'
        };
        return mapping[ext] || 'auto';
    }

    private displayResults(data: any, options: ScanOptions): void {
        if (options.format === 'json') {
            console.log(JSON.stringify(data, null, 2));
            return;
        }

        const findings = data.findings || [];
        
        if (findings.length === 0) {
            console.log(chalk.green('✅ Aucun problème de sécurité détecté'));
            return;
        }

        console.log(chalk.red(`\n🚨 ${findings.length} problème(s) détecté(s):\n`));

        const severityColors = {
            critical: chalk.red.bold,
            high: chalk.red,
            medium: chalk.yellow,
            low: chalk.blue,
            info: chalk.gray
        };

        findings.forEach((finding: any, index: number) => {
            const colorFn = severityColors[finding.severity as keyof typeof severityColors] || chalk.white;
            
            console.log(`${index + 1}. ${colorFn(finding.severity.toUpperCase())}: ${finding.title}`);
            console.log(`   ${finding.description}`);
            if (finding.line) {
                console.log(chalk.gray(`   Ligne ${finding.line}`));
            }
            console.log(chalk.cyan(`   💡 ${finding.remediation}`));
            console.log('');
        });
    }

    private displayDirectoryResults(results: any[], options: ScanOptions): void {
        if (results.length === 0) {
            console.log(chalk.green('✅ Aucun problème de sécurité détecté'));
            return;
        }

        let totalFindings = 0;
        results.forEach(result => totalFindings += result.findings.length);

        console.log(chalk.red(`\n🚨 ${totalFindings} problème(s) dans ${results.length} fichier(s):\n`));

        results.forEach(result => {
            console.log(chalk.bold(`📄 ${path.relative(process.cwd(), result.file)}`));
            result.findings.forEach((finding: any, index: number) => {
                console.log(`  ${index + 1}. ${finding.severity.toUpperCase()}: ${finding.title}`);
                if (finding.line) {
                    console.log(`     Ligne ${finding.line}`);
                }
            });
            console.log('');
        });
    }
}

// Configuration de la CLI
const program = new Command();
const cli = new WebSentinelCLI();

program
    .name('web-sentinel')
    .description('Web Sentinel Security Scanner CLI')
    .version('1.0.0');

program
    .command('scan <path>')
    .description('Scanner un fichier ou dossier')
    .option('-l, --language <langs>', 'Langages à scanner (séparés par des virgules)')
    .option('-e, --exclude <patterns>', 'Patterns à exclure')
    .option('-s, --severity-min <level>', 'Niveau de sévérité minimum', 'medium')
    .option('-o, --output <file>', 'Fichier de sortie')
    .option('-f, --format <format>', 'Format de sortie (json|text)', 'text')
    .action(async (filePath: string, options: any) => {
        const isDirectory = fs.statSync(filePath).isDirectory();
        
        const scanOptions: ScanOptions = {
            language: options.language?.split(','),
            exclude: options.exclude?.split(','),
            severityMin: options.severityMin,
            output: options.output,
            format: options.format
        };

        if (isDirectory) {
            await cli.scanDirectory(filePath, scanOptions);
        } else {
            await cli.scanFile(filePath, scanOptions);
        }
    });

program
    .command('init')
    .description('Initialiser la configuration Web Sentinel')
    .action(async () => {
        const configPath = path.join(process.cwd(), '.websentinel.json');
        
        const config = {
            apiUrl: 'https://api.web-sentinel.com',
            apiKey: '// Votre clé API ici',
            options: {
                severityMin: 'medium',
                autoScan: false
            }
        };

        fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
        console.log(chalk.green(`✅ Configuration créée: ${configPath}`));
        console.log(chalk.yellow('⚠️  N\'oubliez pas de configurer votre clé API'));
    });

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

export { WebSentinelCLI };