#!/usr/bin/env node
/**
 * Node.js 依赖安装和同步脚本
 * 功能：检查、安装 package.json 中的依赖，然后同步所有已安装的包到 dependencies.txt
 */

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

// 获取脚本所在目录和项目根目录
const scriptDir = __dirname;
const projectRoot = path.dirname(path.dirname(scriptDir));
const packageJsonPath = path.join(projectRoot, 'package.json');
const dependenciesFile = path.join(scriptDir, 'dependencies.txt');
const nodeModulesPath = path.join(projectRoot, 'node_modules');

// 颜色输出函数
const colors = {
    reset: '\x1b[0m',
    red: '\x1b[31m',
    green: '\x1b[32m',
    yellow: '\x1b[33m',
    cyan: '\x1b[36m',
    white: '\x1b[37m'
};

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

// 检查 package.json 是否存在
if (!fs.existsSync(packageJsonPath)) {
    log('[X] package.json not found', 'red');
    process.exit(1);
}

// 读取 package.json
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
const allDependencies = {};

// 收集所有依赖
if (packageJson.dependencies) {
    Object.keys(packageJson.dependencies).forEach(depName => {
        allDependencies[depName] = {
            version: packageJson.dependencies[depName],
            type: 'dependency'
        };
    });
}

if (packageJson.devDependencies) {
    Object.keys(packageJson.devDependencies).forEach(depName => {
        allDependencies[depName] = {
            version: packageJson.devDependencies[depName],
            type: 'devDependency'
        };
    });
}

// 快速获取已安装的包列表（直接从 node_modules 文件夹读取）
function getInstalledPackagesFromFilesystem() {
    const installedPackages = new Set();
    
    if (!fs.existsSync(nodeModulesPath)) {
        return installedPackages;
    }
    
    try {
        const entries = fs.readdirSync(nodeModulesPath, { withFileTypes: true });
        
        for (const entry of entries) {
            if (entry.isDirectory()) {
                const packageName = entry.name;
                
                // 跳过特殊目录
                if (packageName.startsWith('.') || packageName === 'node_modules') {
                    continue;
                }
                
                // 检查是否是有效的包（有 package.json）
                const packageJsonPath = path.join(nodeModulesPath, packageName, 'package.json');
                if (fs.existsSync(packageJsonPath)) {
                    installedPackages.add(packageName.toLowerCase());
                }
                
                // 处理 scoped 包（如 @babel/core）
                if (packageName.startsWith('@')) {
                    try {
                        const scopedPath = path.join(nodeModulesPath, packageName);
                        const scopedEntries = fs.readdirSync(scopedPath, { withFileTypes: true });
                        for (const scopedEntry of scopedEntries) {
                            if (scopedEntry.isDirectory()) {
                                const scopedPackageName = `${packageName}/${scopedEntry.name}`;
                                const scopedPackageJsonPath = path.join(scopedPath, scopedEntry.name, 'package.json');
                                if (fs.existsSync(scopedPackageJsonPath)) {
                                    installedPackages.add(scopedPackageName.toLowerCase());
                                }
                            }
                        }
                    } catch (error) {
                        // 忽略错误
                    }
                }
            }
        }
    } catch (error) {
        // 忽略错误
    }
    
    return installedPackages;
}

// 快速检查缺失的依赖（使用文件系统）
const missingDependencies = [];
let installedCount = 0;
let missingCount = 0;

// 一次性获取所有已安装的包（只检查一次文件系统）
const installedPackagesSet = getInstalledPackagesFromFilesystem();

const depNames = Object.keys(allDependencies).sort();

for (const depName of depNames) {
    const depNameLower = depName.toLowerCase();
    
    // 快速检查（使用已获取的集合）
    if (installedPackagesSet.has(depNameLower)) {
        installedCount++;
    } else {
        missingDependencies.push(depName);
        missingCount++;
    }
}

// Install missing dependencies with retry loop
let maxRetries = 5;
let retryCount = 0;
let currentMissing = [...missingDependencies];

while (currentMissing.length > 0 && retryCount < maxRetries) {
    if (retryCount > 0) {
        log(`\nRetry ${retryCount}/${maxRetries - 1}: Re-checking missing dependencies...`, 'cyan');
    } else {
        log(`[X] Missing ${currentMissing.length} package(s) out of ${Object.keys(allDependencies).length}`, 'red');
        log('Missing dependencies:', 'yellow');
        currentMissing.forEach(missing => {
            log(`  - ${missing}`, 'red');
        });
    }
    
    log('\nInstalling missing dependencies...', 'yellow');
    
    // Switch to project root directory
    process.chdir(projectRoot);
    
    // Try multiple npm registries in order
    const registries = [
        { name: 'Tencent Cloud', url: 'https://mirrors.cloud.tencent.com/npm/' },
        { name: 'Huawei Cloud', url: 'https://repo.huaweicloud.com/repository/npm/' },
        { name: 'Taobao Mirror', url: 'https://registry.npmmirror.com' }
    ];
    
    let installSuccess = false;
    for (const registry of registries) {
        log(`\nTrying ${registry.name} registry...`, 'cyan');
        execSync(`npm config set registry ${registry.url}`, { 
            stdio: 'inherit',
            cwd: projectRoot
        });
        
        // Run npm install with output visible
        const installResult = execSync('npm install', { 
            stdio: 'inherit',
            cwd: projectRoot,
            encoding: 'utf-8'
        });
        
        // Check if installation was successful by re-checking packages
        const installedPackagesSetAfterInstall = getInstalledPackagesFromFilesystem();
        const stillMissing = [];
        for (const depName of depNames) {
            const depNameLower = depName.toLowerCase();
            if (!installedPackagesSetAfterInstall.has(depNameLower)) {
                stillMissing.push(depName);
            }
        }
        
        if (stillMissing.length === 0) {
            installSuccess = true;
            log(`\n[OK] Installation successful using ${registry.name} registry`, 'green');
            break;
        } else {
            log(`\n[~] ${stillMissing.length} package(s) still missing, trying next registry...`, 'yellow');
        }
    }
    
    if (!installSuccess) {
        // Final attempt with original registry
        log('\nTrying default npm registry...', 'cyan');
        execSync('npm config set registry https://registry.npmjs.org/', { 
            stdio: 'inherit',
            cwd: projectRoot
        });
        execSync('npm install', { 
            stdio: 'inherit',
            cwd: projectRoot
        });
    }
    
    // Re-check installed packages after installation
    log('\nRe-checking installed packages...', 'cyan');
    const installedPackagesSetAfterInstall = getInstalledPackagesFromFilesystem();
    const stillMissing = [];
    
    for (const depName of depNames) {
        const depNameLower = depName.toLowerCase();
        if (!installedPackagesSetAfterInstall.has(depNameLower)) {
            stillMissing.push(depName);
        }
    }
    
    if (stillMissing.length === 0) {
        log('[OK] All dependencies installed successfully', 'green');
        currentMissing = [];
        break;
    } else if (stillMissing.length < currentMissing.length) {
        log(`[~] Progress: ${currentMissing.length - stillMissing.length} package(s) installed, ${stillMissing.length} remaining`, 'yellow');
        currentMissing = stillMissing;
        retryCount++;
    } else {
        log(`[X] Still missing ${stillMissing.length} package(s)`, 'red');
        stillMissing.forEach(missing => {
            log(`  - ${missing}`, 'red');
        });
        retryCount++;
        currentMissing = stillMissing;
    }
}

if (currentMissing.length > 0) {
    log(`\n[X] Failed to install ${currentMissing.length} package(s) after ${retryCount} attempts:`, 'red');
    currentMissing.forEach(missing => {
        log(`  - ${missing}`, 'red');
    });
    log('\n[WARN] Some packages may require additional setup', 'yellow');
    process.exit(1);
} else if (missingCount === 0) {
    log(`[OK] All dependencies are installed (${Object.keys(allDependencies).length} packages)`, 'green');
}

// 快速同步所有已安装的依赖到 dependencies.txt（只读取根级包，静默执行）
function syncInstalledPackagesToFile() {
    const syncResult = [];
    
    if (!fs.existsSync(nodeModulesPath)) {
        return syncResult;
    }
    
    try {
        const entries = fs.readdirSync(nodeModulesPath, { withFileTypes: true });
        
        for (const entry of entries) {
            if (entry.isDirectory()) {
                const packageName = entry.name;
                
                // 跳过特殊目录
                if (packageName.startsWith('.') || packageName === 'node_modules') {
                    continue;
                }
                
                // 处理普通包
                const packageJsonPath = path.join(nodeModulesPath, packageName, 'package.json');
                if (fs.existsSync(packageJsonPath)) {
                    try {
                        const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
                        if (pkg.name && pkg.version) {
                            syncResult.push(`${pkg.name}==${pkg.version}`);
                        }
                    } catch (error) {
                        // 忽略解析错误
                    }
                }
                
                // 处理 scoped 包（如 @babel/core）
                if (packageName.startsWith('@')) {
                    try {
                        const scopedPath = path.join(nodeModulesPath, packageName);
                        const scopedEntries = fs.readdirSync(scopedPath, { withFileTypes: true });
                        for (const scopedEntry of scopedEntries) {
                            if (scopedEntry.isDirectory()) {
                                const scopedPackageJsonPath = path.join(scopedPath, scopedEntry.name, 'package.json');
                                if (fs.existsSync(scopedPackageJsonPath)) {
                                    try {
                                        const pkg = JSON.parse(fs.readFileSync(scopedPackageJsonPath, 'utf-8'));
                                        if (pkg.name && pkg.version) {
                                            syncResult.push(`${pkg.name}==${pkg.version}`);
                                        }
                                    } catch (error) {
                                        // 忽略解析错误
                                    }
                                }
                            }
                        }
                    } catch (error) {
                        // 忽略错误
                    }
                }
            }
        }
    } catch (error) {
        // 忽略错误
    }
    
    return syncResult;
}

// 同步所有已安装的依赖到 dependencies.txt（快速方法，静默执行）
const syncResult = syncInstalledPackagesToFile();

// 去重并排序
const uniqueResult = [...new Set(syncResult)].sort();

// 写入文件（UTF-8 编码）
fs.writeFileSync(dependenciesFile, uniqueResult.join('\n') + '\n', 'utf-8');

process.exit(0);
