#!/usr/bin/env node
import * as path from 'node:path';
import * as fs from 'node:fs';
import { err, run, makeExecutable, getDebianVersion, getScriptsDir, info } from './lib/util.mjs';
import { parseOptions, Enum, Architectures } from './lib/options.mjs';

// Check System
if (process.getuid() !== 0) {
    err("Must Run As Root!");
}
if (!fs.existsSync('/etc/debian_version')) {
    err('Non-Debian OS Detected');
}

// Options
const Modes = new Enum([
    'Build',
    'Test',
    'SDK'
]);
const options = parseOptions([
    ['mode', Modes],
    ['architecture', Architectures]
], [], null);

// Setup Backports If Needed
const debianVersion = getDebianVersion();
info('OS Version: ' + debianVersion);
let backportsSuffix = '';
if (debianVersion === 'bullseye') {
    const repo = debianVersion + '-backports';
    const source = `deb http://deb.debian.org/debian ${repo} main\n`;
    fs.writeFileSync(`/etc/apt/sources.list.d/${repo}.list`, source);
    backportsSuffix = '/' + repo;
}

// Update APT
let archSuffix = '';
if (options.architecture !== Architectures.Host) {
    const arch = options.architecture.name;
    run(['dpkg', '--add-architecture', arch]);
    archSuffix = ':' + arch;
}
run(['apt-get', 'update']);
run(['apt-get', 'dist-upgrade', '-y']);

// Install Packages
const packages = [];
function addPackageForBuild(...arr) {
    // The machine the package is built on.
    packages.push(...arr);
}
function addPackageForHost(...arr) {
    // The machine the package is built for.
    for (const name of arr) {
        packages.push(name + archSuffix);
    }
}

// Build Dependencies
const handlers = new Map();
handlers.set(Modes.Build, function () {
    // Build Dependencies
    addPackageForBuild(
        'git',
        'cmake' + backportsSuffix,
        'ninja-build'
    );

    // Compiler
    if (options.architecture === Architectures.Host) {
        addPackageForBuild('gcc', 'g++');
    } else {
        addPackageForBuild('crossbuild-essential-' + options.architecture.name);
    }

    // Main Dependencies
    addPackageForHost('libopenal-dev');

    // GLFW Dependencies
    addPackageForBuild('libwayland-bin');
    addPackageForHost(
        'libwayland-dev',
        'libxkbcommon-dev',
        'libx11-dev',
        'libxcursor-dev',
        'libxi-dev',
        'libxinerama-dev',
        'libxrandr-dev',
        'libxext-dev'
    );

    // QEMU Dependencies
    addPackageForBuild(
        'python3',
        'python3-venv',
        `python3-tomli` + backportsSuffix
    );
    addPackageForHost('libglib2.0-dev');

    // AppImage Dependencies
    addPackageForBuild(
        'appstream',
        'zsync'
    );

    // Download AppImageTool
    function getAppImageArch() {
        switch (process.arch) {
            case 'x64': return 'x86_64';
            case 'arm64': return 'aarch64';
            case 'arm': return 'armhf';
            default: err('Unsupported Build Architecture');
        }
    }
    let appimagetool = '/opt/appimagetool';
    run(['wget', '-O', appimagetool, `https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${getAppImageArch()}.AppImage`]);
    makeExecutable(appimagetool);
    run([getScriptsDir() + '/fix-appimage-for-docker.sh', appimagetool]);
    const script = `#!/bin/sh\nexec ${appimagetool} --appimage-extract-and-run "$@"\n`;
    appimagetool = '/usr/local/bin/' + path.basename(appimagetool);
    fs.writeFileSync(appimagetool, script);
    makeExecutable(appimagetool);
});

// Testing Dependencies
handlers.set(Modes.Test, function () {
    addPackageForHost(
        'libc6',
        'libstdc++6',
        'libopenal1',
        'libglib2.0-0'
    );
});

// SDK Usage Dependencies
handlers.set(Modes.SDK, function () {
    addPackageForBuild(
        'cmake' + backportsSuffix,
        'ninja-build',
        'g++-arm-linux-gnueabihf',
        'gcc-arm-linux-gnueabihf'
    );
});

// Run
handlers.get(options.mode)();

// Install Packages
run(['apt-get', 'install', '--no-install-recommends', '-y', ...packages]);