#!/usr/bin/env node
/**
 * Unified build system for msger-native
 * Reads build-config.json to determine which platforms to build
 */

import { execSync, spawnSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { platform } from 'os';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

interface BuildConfig {
    platforms: {
        windows?: boolean;
        wsl?: boolean;
        pi?: boolean;
        arm64?: boolean;
    };
    options?: {
        release?: boolean;
        verbose?: boolean;
        piHost?: string;
        piProjectPath?: string;
    };
}

function isWSL(): boolean {
    try {
        const release = fs.readFileSync('/proc/version', 'utf8');
        return release.toLowerCase().includes('microsoft');
    } catch {
        return false;
    }
}

function isWindows(): boolean {
    return platform() === 'win32' && !isWSL();
}

function getCleanPathForWindows(): string {
    // Remove Git's /usr/bin from PATH to avoid link.exe conflict with VS linker
    const currentPath = process.env.PATH || '';
    const pathParts = currentPath.split(';');
    const filteredParts = pathParts.filter(part => {
        const lower = part.toLowerCase();
        return !lower.includes('git\\usr\\bin') && !lower.includes('git/usr/bin');
    });
    return filteredParts.join(';');
}

/**
 * Execute a command in WSL using spawn to avoid quoting issues
 */
function wslExec(command: string, args: string[], options?: { stdio?: 'inherit' | 'pipe'; encoding?: BufferEncoding }): { success: boolean; output: string; error: string } {
    const result = spawnSync('wsl', [command, ...args], {
        stdio: options?.stdio || 'pipe',
        encoding: options?.encoding || 'utf-8'
    });

    return {
        success: result.status === 0,
        output: result.stdout?.toString() || '',
        error: result.stderr?.toString() || ''
    };
}

/**
 * Convert Windows path to WSL path
 */
function toWSLPath(winPath: string): string {
    // Convert backslashes to forward slashes for wslpath
    const normalizedPath = winPath.replace(/\\/g, '/');
    const result = spawnSync('wsl', ['wslpath', normalizedPath], { encoding: 'utf-8' });
    if (result.status !== 0) {
        const error = result.stderr?.toString() || 'unknown error';
        throw new Error(`Failed to convert path: ${winPath} - ${error}`);
    }
    return result.stdout.trim();
}

function needsRebuild(binaryPath: string, sourceDirs: string[]): boolean {
    if (!fs.existsSync(binaryPath)) {
        return true;
    }

    const binaryTime = fs.statSync(binaryPath).mtime.getTime();

    function checkDir(dirPath: string): boolean {
        const entries = fs.readdirSync(dirPath, { withFileTypes: true });
        for (const entry of entries) {
            const fullPath = path.join(dirPath, entry.name);
            if (entry.isFile()) {
                const fileTime = fs.statSync(fullPath).mtime.getTime();
                if (fileTime > binaryTime) {
                    console.log(`  📝 Source file changed: ${entry.name}`);
                    return true;
                }
            } else if (entry.isDirectory()) {
                if (checkDir(fullPath)) {
                    return true;
                }
            }
        }
        return false;
    }

    for (const sourcePath of sourceDirs) {
        if (!fs.existsSync(sourcePath)) continue;

        const stats = fs.statSync(sourcePath);
        if (stats.isFile()) {
            const fileTime = stats.mtime.getTime();
            if (fileTime > binaryTime) {
                console.log(`  📝 Source file changed: ${sourcePath}`);
                return true;
            }
        } else if (stats.isDirectory()) {
            if (checkDir(sourcePath)) {
                return true;
            }
        }
    }

    return false;
}

/**
 * Load build configuration from JSON file
 */
function loadConfig(): BuildConfig {
    const configPath = path.join(__dirname, 'build-config.json');

    if (!fs.existsSync(configPath)) {
        console.error('❌ build-config.json not found');
        process.exit(1);
    }

    try {
        const content = fs.readFileSync(configPath, 'utf-8');
        return JSON.parse(content);
    } catch (error: any) {
        console.error(`❌ Failed to parse build-config.json: ${error.message}`);
        process.exit(1);
    }
}

function timestamp(): string {
    const now = new Date();
    return now.toTimeString().split(' ')[0]; // HH:MM:SS
}

/**
 * Build Windows binary
 */
function buildWindows(nativeDir: string, binDir: string, verbose: boolean): boolean {
    console.log(`\n[${timestamp()}] 📦 Building Windows x64 binary...`);

    const binaryPath = path.join(binDir, 'msgernative.exe');
    const sourceDirs = [
        path.join(nativeDir, 'src'),
        path.join(nativeDir, 'Cargo.toml'),
        path.join(nativeDir, 'build.rs')
    ];

    if (!needsRebuild(binaryPath, sourceDirs)) {
        console.log(`  [${timestamp()}] ✅ Binary is up to date, skipping build`);
        const stats = fs.statSync(binaryPath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
        return true;
    }

    console.log(`  [${timestamp()}] 🔧 Fixing PATH to use VS linker instead of Git link.exe`);
    const cleanPath = getCleanPathForWindows();

    try {
        execSync('cargo build --release', {
            cwd: nativeDir,
            stdio: verbose ? 'inherit' : 'pipe',
            env: { ...process.env, PATH: cleanPath }
        });

        // Copy to bin directory
        if (!fs.existsSync(binDir)) {
            fs.mkdirSync(binDir, { recursive: true });
        }

        const sourcePath = path.join(nativeDir, 'target', 'release', 'msgernative.exe');
        fs.copyFileSync(sourcePath, binaryPath);

        // Copy msger icons (.ico and .png) to bin directory
        const winIcoSource = path.join(nativeDir, '..', 'msger.ico');
        const winIcoDest = path.join(binDir, 'msger.ico');
        const winPngSource = path.join(nativeDir, '..', 'msger.png');
        const winPngDest = path.join(binDir, 'msger.png');
        
        if (fs.existsSync(winIcoSource)) {
            fs.copyFileSync(winIcoSource, winIcoDest);
            console.log(`  [${timestamp()}] 🎨 Icon (ICO) copied to bin directory`);
        }
        if (fs.existsSync(winPngSource)) {
            fs.copyFileSync(winPngSource, winPngDest);
            console.log(`  [${timestamp()}] 🎨 Icon (PNG) copied to bin directory`);
        }

        const stats = fs.statSync(binaryPath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        console.log(`  [${timestamp()}] ✅ Windows x64 binary completed`);
        console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
        return true;
    } catch (error: any) {
        console.error(`  [${timestamp()}] ❌ Windows build failed: ${error.message}`);
        return false;
    }
}

/**
 * Build WSL Linux binary
 */
function buildWSL(nativeDir: string, binDir: string, verbose: boolean): boolean {
    console.log(`\n[${timestamp()}] 📦 Building WSL Linux x64 binary...`);

    const binaryPath = path.join(binDir, 'msgernative');
    const wslNativeDir = toWSLPath(nativeDir);

    try {
        // Use rustup's cargo, not system cargo
        const cmd = `export PATH="$HOME/.cargo/bin:$PATH" && cd "${wslNativeDir}" && cargo build --release --target x86_64-unknown-linux-gnu`;
        const result = wslExec('bash', ['-c', cmd], {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        if (!result.success) {
            throw new Error(result.error || 'Build failed');
        }

        // Copy to bin directory
        if (!fs.existsSync(binDir)) {
            fs.mkdirSync(binDir, { recursive: true });
        }

        const sourcePath = path.join(nativeDir, 'target', 'x86_64-unknown-linux-gnu', 'release', 'msgernative');
        fs.copyFileSync(sourcePath, binaryPath);
        fs.chmodSync(binaryPath, 0o755);

        // Copy msger.png icon to bin directory (Linux uses PNG)
        const wslIconSource = path.join(nativeDir, '..', 'msger.png');
        const wslIconDest = path.join(binDir, 'msger.png');
        if (fs.existsSync(wslIconSource)) {
            fs.copyFileSync(wslIconSource, wslIconDest);
            console.log(`  [${timestamp()}] 🎨 Icon (PNG) copied to bin directory`);
        }

        const stats = fs.statSync(binaryPath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        console.log(`  [${timestamp()}] ✅ WSL Linux x64 binary completed`);
        console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
        return true;
    } catch (error: any) {
        console.error(`  [${timestamp()}] ❌ WSL build failed: ${error.message}`);
        return false;
    }
}

/**
 * Check if Rust is installed on Pi
 */
function checkPiRust(piHost: string): boolean {
    try {
        // Source cargo env before checking (cargo won't be in PATH until sourced)
        const result = execSync(`ssh ${piHost} "source ~/.cargo/env 2>/dev/null && command -v cargo"`, {
            encoding: 'utf-8',
            stdio: 'pipe'
        });
        return result.trim().length > 0;
    } catch {
        return false;
    }
}

/**
 * Install Rust on Pi
 */
function installPiRust(piHost: string, verbose: boolean): boolean {
    console.log(`  [${timestamp()}] 📦 Rust not found on Pi, installing...`);

    try {
        // Install Rust using rustup
        execSync(`ssh ${piHost} "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"`, {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        console.log(`  [${timestamp()}] ✅ Rust installed on Pi`);
        return true;
    } catch (error: any) {
        console.error(`  [${timestamp()}] ❌ Failed to install Rust on Pi: ${error.message}`);
        return false;
    }
}

/**
 * Build Raspberry Pi ARM64 binary
 */
function buildPi(nativeDir: string, binDir: string, verbose: boolean, piHost: string, piProjectPath: string): boolean {
    console.log(`\n[${timestamp()}] 📦 Building Raspberry Pi ARM64 binary...`);
    console.log(`  Target: ${piHost}:${piProjectPath}`);

    const binaryPath = path.join(binDir, 'msgernative-linux-aarch64');
    const sourceDirs = [
        path.join(nativeDir, 'src'),
        path.join(nativeDir, 'Cargo.toml'),
        path.join(nativeDir, 'build.rs')
    ];

    try {
        // Check if rebuild is needed
        if (!needsRebuild(binaryPath, sourceDirs)) {
            console.log(`  [${timestamp()}] ✅ Binary is up to date, skipping build`);
            const stats = fs.statSync(binaryPath);
            const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
            console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
            return true;
        }

        // Check if Rust is installed on Pi, install if missing
        if (!checkPiRust(piHost)) {
            if (!installPiRust(piHost, verbose)) {
                return false;
            }
        }

        // Copy source files to Pi
        console.log(`  [${timestamp()}] 📤 Copying source files to Pi...`);
        execSync(`ssh ${piHost} "mkdir -p ${piProjectPath}"`, {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        // Copy only necessary files for compilation: src/, Cargo.toml, build.rs
        const filesToCopy = ['src', 'Cargo.toml', 'Cargo.lock', 'build.rs'];
        for (const file of filesToCopy) {
            const sourcePath = path.join(nativeDir, file);
            if (fs.existsSync(sourcePath)) {
                console.log(`  [${timestamp()}]   → ${file}`);
                execSync(`scp -r "${sourcePath}" ${piHost}:${piProjectPath}/`, {
                    stdio: verbose ? 'inherit' : 'pipe'
                });
            }
        }

        // Build remotely on Pi (source cargo environment in case just installed)
        console.log(`  [${timestamp()}] 🔗 Building on remote Raspberry Pi...`);
        execSync(`ssh ${piHost} "source ~/.cargo/env && cd ${piProjectPath} && cargo build --release"`, {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        // Copy back only the compiled binary
        console.log(`  [${timestamp()}] 📥 Copying binary from Pi...`);
        if (!fs.existsSync(binDir)) {
            fs.mkdirSync(binDir, { recursive: true });
        }

        execSync(`scp ${piHost}:${piProjectPath}/target/release/msgernative "${binaryPath}"`, {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        fs.chmodSync(binaryPath, 0o755);

        const stats = fs.statSync(binaryPath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        console.log(`  [${timestamp()}] ✅ Raspberry Pi ARM64 binary completed`);
        console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
        return true;
    } catch (error: any) {
        console.error(`  [${timestamp()}] ❌ Pi build failed: ${error.message}`);
        return false;
    }
}

/**
 * Check if ARM64 toolchain is installed
 */
function checkARM64Toolchain(): boolean {
    // Check with PATH set to include cargo bin
    // Also verify ARM64 libraries are present (linker needs these)
    const cmd = 'export PATH="$HOME/.cargo/bin:$PATH" && which rustup && rustup target list --installed | grep -q aarch64-unknown-linux-gnu && which aarch64-linux-gnu-gcc && dpkg -l | grep -q "libwebkit2gtk-4.1.*arm64"';
    const result = wslExec('bash', ['-c', cmd]);
    return result.success;
}

/**
 * Install ARM64 toolchain
 */
function installARM64Toolchain(verbose: boolean): boolean {
    console.log(`  [${timestamp()}] 📦 ARM64 toolchain not found, installing...`);

    // Get project root (parent of msger-native) and convert to WSL path
    const projectRoot = path.resolve(__dirname, '..', '..');
    const wslPath = toWSLPath(projectRoot);

    // Check if rustup is installed, if not install Rust first
    const rustupCheck = wslExec('which', ['rustup']);
    if (!rustupCheck.success) {
        console.log(`  [${timestamp()}] 📦 Installing Rust in WSL...`);
        const rustInstallScript = `${wslPath}/msger-native/pibuild/install-rust-wsl.sh`;
        const rustInstall = wslExec('bash', [rustInstallScript], { stdio: verbose ? 'inherit' : 'pipe' });

        if (!rustInstall.success) {
            console.error(`  [${timestamp()}] ❌ Failed to install Rust in WSL`);
            if (!verbose && rustInstall.error) {
                console.error(`  [${timestamp()}] ${rustInstall.error}`);
            }
            return false;
        }
        console.log(`  [${timestamp()}] ✅ Rust installed in WSL`);
    }

    // Now install ARM64 cross-compilation toolchain
    const scriptPath = `${wslPath}/msger-native/pibuild/setup-arm64-toolchain.sh`;
    const result = wslExec('bash', [scriptPath], { stdio: verbose ? 'inherit' : 'pipe' });

    if (!result.success) {
        console.error(`  [${timestamp()}] ❌ Failed to install ARM64 toolchain`);
        if (!verbose && result.error) {
            console.error(`  [${timestamp()}] ${result.error}`);
        }
        return false;
    }

    console.log(`  [${timestamp()}] ✅ ARM64 toolchain installed successfully`);
    return true;
}

/**
 * Build generic ARM64 binary via cross-compilation
 */
function buildARM64(nativeDir: string, binDir: string, verbose: boolean): boolean {
    console.log(`\n[${timestamp()}] 📦 Building Linux ARM64 binary (cross-compile)...`);

    // Check and install toolchain if needed
    if (!checkARM64Toolchain()) {
        console.log(`  [${timestamp()}] ⚙️  Checking ARM64 toolchain...`);
        if (!installARM64Toolchain(verbose)) {
            return false;
        }
    }

    const binaryPath = path.join(binDir, 'msgernative-linux-aarch64');
    const wslNativeDir = toWSLPath(nativeDir);

    console.log(`  [${timestamp()}] 🔨 Compiling ARM64 binary (this may take 2-5 minutes)...`);

    try {
        // Use rustup's cargo, not system cargo
        // Set PKG_CONFIG_ALLOW_CROSS to enable cross-compilation
        const cmd = `export PATH="$HOME/.cargo/bin:$PATH" && export PKG_CONFIG_ALLOW_CROSS=1 && cd "${wslNativeDir}" && cargo build --release --target aarch64-unknown-linux-gnu`;
        const result = wslExec('bash', ['-c', cmd], {
            stdio: verbose ? 'inherit' : 'pipe'
        });

        if (!result.success) {
            throw new Error(result.error || 'Build failed');
        }

        // Copy to bin directory
        if (!fs.existsSync(binDir)) {
            fs.mkdirSync(binDir, { recursive: true });
        }

        const sourcePath = path.join(nativeDir, 'target', 'aarch64-unknown-linux-gnu', 'release', 'msgernative');
        fs.copyFileSync(sourcePath, binaryPath);
        fs.chmodSync(binaryPath, 0o755);

        const stats = fs.statSync(binaryPath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        console.log(`  [${timestamp()}] ✅ Linux ARM64 binary completed`);
        console.log(`  [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
        return true;
    } catch (error: any) {
        console.error(`  [${timestamp()}] ❌ ARM64 build failed: ${error.message}`);
        return false;
    }
}

/**
 * Main build orchestrator
 */
function main() {
    console.log('🚀 msger-native unified builder\n');

    const config = loadConfig();
    const verbose = config.options?.verbose ?? false;
    const release = config.options?.release ?? true;

    const nativeDir = path.join(__dirname, '..');
    const binDir = path.join(nativeDir, 'bin');

    const enabledPlatforms = Object.entries(config.platforms)
        .filter(([_, enabled]) => enabled)
        .map(([name]) => name);

    console.log(`📋 Build configuration:`);
    console.log(`   Mode: ${release ? 'release' : 'debug'}`);
    console.log(`   Platforms: ${enabledPlatforms.join(', ') || 'none'}\n`);

    if (enabledPlatforms.length === 0) {
        console.log('⚠️  No platforms enabled in build-config.json');
        process.exit(0);
    }

    const results: { platform: string; success: boolean }[] = [];

    // Build each enabled platform
    if (config.platforms.windows) {
        results.push({ platform: 'windows', success: buildWindows(nativeDir, binDir, verbose) });
    }

    if (config.platforms.wsl) {
        results.push({ platform: 'wsl', success: buildWSL(nativeDir, binDir, verbose) });
    }

    if (config.platforms.pi) {
        const piHost = config.options?.piHost ?? 'pi4c';
        const piProjectPath = config.options?.piProjectPath ?? '/home/pi/dev/msger/msger-native';
        results.push({ platform: 'pi', success: buildPi(nativeDir, binDir, verbose, piHost, piProjectPath) });
    }

    if (config.platforms.arm64) {
        results.push({ platform: 'arm64', success: buildARM64(nativeDir, binDir, verbose) });
    }

    // Summary
    console.log('\n' + '='.repeat(50));
    console.log('📊 Build Summary:');
    console.log('='.repeat(50));

    for (const result of results) {
        const status = result.success ? '✅' : '❌';
        console.log(`${status} ${result.platform}`);
    }

    const successCount = results.filter(r => r.success).length;
    const totalCount = results.length;

    console.log('='.repeat(50));
    console.log(`\n🎉 Completed: ${successCount}/${totalCount} builds successful\n`);

    if (successCount < totalCount) {
        process.exit(1);
    }
}

main();
