// Custom Electron Forge maker that produces Arch Linux .pkg.tar.zst packages
// via makepkg. Runs only on Linux with makepkg available (i.e. an Arch host).
//
// CJS on purpose: forge.config.cjs require()s us.

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

const MakerBase = require('@electron-forge/maker-base').default;

const ARCH_MAP = { x64: 'x86_64', arm64: 'aarch64', ia32: 'i686', armv7l: 'armv7h' };

class MakerPacman extends MakerBase {
    name = 'pacman';
    defaultPlatforms = ['linux'];

    isSupportedOnCurrentPlatform() {
        if (process.platform !== 'linux') return false;
        try {
            execSync('command -v makepkg', { stdio: 'ignore' });
            return true;
        } catch {
            return false;
        }
    }

    async make({ dir, makeDir, targetArch, packageJSON, appName }) {
        const pkgArch = ARCH_MAP[targetArch] || targetArch;

        const cfg = this.config || {};
        const pkgName = (cfg.name || appName || packageJSON.name).toLowerCase();
        // pacman pkgver disallows '-'; map prerelease tags through.
        const pkgVersion = String(packageJSON.version || '0.0.0').replace(/-/g, '_');
        const pkgDesc = (cfg.description || packageJSON.description || '').replace(/"/g, '\\"');
        const maintainer = cfg.maintainer || 'unknown';
        const homepage = cfg.homepage || packageJSON.homepage || '';
        const license = cfg.license || 'custom';
        const bin = cfg.bin || pkgName;
        const execName = cfg.executableName || appName || pkgName;
        const mimeTypes = cfg.mimeType || [];
        const depends = cfg.depends || [];
        const iconSrc = cfg.icon;

        const outDir = path.resolve(path.join(makeDir, 'pacman', targetArch));
        await this.ensureDirectory(outDir);

        // Clean prior contents so makepkg starts fresh each run.
        for (const f of fs.readdirSync(outDir)) {
            fs.rmSync(path.join(outDir, f), { recursive: true, force: true });
        }

        // Wrapper script — execs the packaged Electron binary, forwards args (incl. rowboat:// URLs).
        fs.writeFileSync(
            path.join(outDir, bin),
            `#!/bin/sh\nexec "/opt/${pkgName}/${execName}" "$@"\n`,
            { mode: 0o755 },
        );

        const desktop = [
            '[Desktop Entry]',
            `Name=${appName || pkgName}`,
            `Comment=${pkgDesc}`,
            `Exec=${bin} %U`,
            `Icon=${pkgName}`,
            'Type=Application',
            'Categories=Utility;',
            'Terminal=false',
            mimeTypes.length ? `MimeType=${mimeTypes.join(';')};` : null,
            '',
        ].filter(Boolean).join('\n');
        fs.writeFileSync(path.join(outDir, `${pkgName}.desktop`), desktop);

        const sources = [bin, `${pkgName}.desktop`];
        let iconInstall = '';
        if (iconSrc && fs.existsSync(iconSrc)) {
            fs.copyFileSync(iconSrc, path.join(outDir, 'icon.png'));
            sources.push('icon.png');
            iconInstall = `  install -Dm644 "$srcdir/icon.png" "$pkgdir/usr/share/icons/hicolor/512x512/apps/${pkgName}.png"`;
        }

        const sumsLine = sources.map(() => "'SKIP'").join(' ');
        const sourceLine = sources.map((s) => `'${s}'`).join(' ');
        const dependsLine = depends.map((d) => `'${d}'`).join(' ');
        // Embed the packager output dir as a bash-safe literal.
        const appDirEscaped = dir.replace(/'/g, `'\\''`);

        const pkgbuild = `# Maintainer: ${maintainer}
# Auto-generated by maker-pacman.cjs — do not edit by hand.
pkgname=${pkgName}
pkgver=${pkgVersion}
pkgrel=1
pkgdesc="${pkgDesc}"
arch=('${pkgArch}')
url="${homepage}"
license=('${license}')
depends=(${dependsLine})
options=('!strip' '!debug')
source=(${sourceLine})
sha256sums=(${sumsLine})

_appdir='${appDirEscaped}'

package() {
  install -dm755 "$pkgdir/opt/$pkgname"
  cp -a "$_appdir/." "$pkgdir/opt/$pkgname/"

  # Electron's sandbox helper needs setuid root for the namespace sandbox.
  if [ -f "$pkgdir/opt/$pkgname/chrome-sandbox" ]; then
    chmod 4755 "$pkgdir/opt/$pkgname/chrome-sandbox"
  fi

  install -Dm755 "$srcdir/${bin}" "$pkgdir/usr/bin/${bin}"
  install -Dm644 "$srcdir/${pkgName}.desktop" "$pkgdir/usr/share/applications/${pkgName}.desktop"
${iconInstall}
}
`;
        fs.writeFileSync(path.join(outDir, 'PKGBUILD'), pkgbuild);

        execSync('makepkg -f --noconfirm --nodeps', {
            cwd: outDir,
            stdio: 'inherit',
            env: { ...process.env, PKGEXT: '.pkg.tar.zst', CARCH: pkgArch },
        });

        return fs
            .readdirSync(outDir)
            .filter((f) => f.endsWith('.pkg.tar.zst'))
            .map((f) => path.join(outDir, f));
    }
}

module.exports = MakerPacman;
module.exports.default = MakerPacman;
