"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPackageWithElectronForge = createPackageWithElectronForge;
const logger_1 = require("../../utils/logger");
const core_1 = require("@electron-forge/core");
const path_1 = require("../../utils/path");
const fs_extra_1 = require("fs-extra");
const path_2 = require("path");
const config_service_1 = require("../config/config.service");
const file_1 = require("../../utils/file");
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
const os_1 = require("os");
const child_process_1 = require("child_process");
const error_handler_1 = require("../../utils/error.handler");
const find_package_dir_1 = require("../../utils/find.package.dir");
const logger = logger_1.Logger.getInstance("electronForge");
async function createPackageWithElectronForge() {
    try {
        logger.info("Creating build...");
        // copy forge.config.js from config to root if exists
        await copyForgeConfig();
        // copy PathUtils.getIOCDDir() to PathUtils.getDistDir() in a folder called <name>-<platform>-<arch>/
        const appPackageTempDir = await copyAppToDist();
        // TODO review if need this at all, now that we are using electron forge
        await ensureElectronVersionIsSet();
        // If your app is already prepackaged & signed internally, tell Forge to skip packaging
        const makeResults = await callForgeMake(appPackageTempDir);
        await signArtifacts(makeResults);
        const published = await callForgePublish();
        return { published };
    }
    catch (error) {
        logger.error(`Failed to create package`, error);
        throw error;
    }
    finally {
        // remove copied forge.config.js from root if it was copied
        removeForgeConfig();
    }
}
function removeForgeConfig() {
    const forgeConfigDest = (0, path_2.join)(path_1.PathUtils.getRootDir(), "forge.config.js");
    if ((0, fs_extra_1.existsSync)(forgeConfigDest)) {
        try {
            (0, fs_1.rmSync)(forgeConfigDest);
            logger.debug("Removed temporary forge.config.js from root directory");
        }
        catch (err) {
            logger.warn(`Failed to remove temporary forge.config.js: ${err instanceof Error ? err.message : String(err)}`);
        }
    }
}
async function copyForgeConfig() {
    const forgeConfigSrc = path_1.PathUtils.getForgeConfigPath();
    if (await file_1.FileUtils.exists(forgeConfigSrc)) {
        const forgeConfigDest = (0, path_2.join)(path_1.PathUtils.getRootDir(), "forge.config.js");
        await (0, promises_1.cp)(forgeConfigSrc, forgeConfigDest);
        logger.debug("Copied forge.config.js to root directory for packaging");
    }
    else {
        logger.warn("No forge.config.js found in config directory, using default configuration");
    }
}
async function callForgeMake(appPackageTempDir) {
    let makeTargets = getTargetsFromConfig();
    if (makeTargets.length === 0) {
        throw new error_handler_1.CLIError("No makers configured in forge.config.js. Please configure at least one maker (e.g. Squirrel for Windows, DMG for macOS).", {
            suggestions: [
                "Add at least one maker to the makers array in forge.config.js",
                "Refer to https://www.electronforge.io/config/makers for available makers and configuration examples",
            ],
        });
    }
    const makeOptions = {
        dir: appPackageTempDir,
        skipPackage: true, // <— consume prepackaged app in out/<name>-<platform>-<arch>/
        outDir: path_1.PathUtils.getDistDir(),
        overrideTargets: makeTargets,
    };
    const options = {
        dir: appPackageTempDir,
        makeOptions,
        dryRun: true,
        outDir: path_1.PathUtils.getDistDir(),
    };
    // we call make by actually calling publish with dryRun :((
    logger.debug("Calling publish (dry run) with make options:", JSON.stringify(options, null, 4));
    await core_1.api.publish(options);
    logger.debug("publish (dry run) done");
    // read results from dist/makeResults.json
    const makeResultsJSON = (0, path_2.join)(path_1.PathUtils.getDistDir(), "makeResults.json");
    if ((0, fs_extra_1.existsSync)(makeResultsJSON)) {
        const makeResults = await (0, fs_extra_1.readJson)(makeResultsJSON);
        logger.debug("Read artifacts from dist/makeResults.json successfully!");
        return makeResults;
    }
    else {
        throw new error_handler_1.CLIError("No makeResults found after make process. Please ensure at least one maker is configured correctly in forge.config.js.", {
            suggestions: [
                "Check the output above for any errors during the make process",
                "Ensure that the makers in forge.config.js are configured correctly for your platform",
            ],
        });
    }
}
async function callForgePublish() {
    const publishers = getPublishersFromConfig();
    if (publishers.length === 0) {
        logger.info("No publishers configured in forge.config.js, skipping publish step");
        return false;
    }
    logger.info("Publishing build...");
    const config = {
        dryRunResume: true,
        publishTargets: publishers,
        outDir: path_1.PathUtils.getDistDir(),
    };
    logger.debug(`Calling publish with config `, JSON.stringify(config, null, 4));
    await core_1.api.publish(config);
    logger.info("Build published successfully.");
    return true;
}
/**
 * This function copies the prepackaged app to the dist directory in a platform-specific way
 * This is needed because we skip forge's prepackaging step and we need to ensure that
 * the app is in the correct location for the make process to find it.
 */
async function copyAppToDist() {
    const projectDir = path_1.PathUtils.getIOCDDir();
    const productNameToUseInTempDir = (0, os_1.platform)() === "win32"
        ? config_service_1.ConfigManager.config.productSlug
        : config_service_1.ConfigManager.config.productName;
    let appPackageTempDir = (0, path_2.join)(path_1.PathUtils.getDistDir(), `${productNameToUseInTempDir}-${process.platform}-${process.arch}`);
    if ((0, fs_extra_1.existsSync)(appPackageTempDir)) {
        (0, fs_1.rmSync)(appPackageTempDir, { recursive: true, force: true });
    }
    if ((0, os_1.platform)() === "win32") {
        // on windows copy the whole directory
        logger.debug(`Copying prepackaged app exe from ${projectDir} to ${appPackageTempDir}`);
        await (0, promises_1.cp)(projectDir, appPackageTempDir, { recursive: true });
        logger.debug(`Copied prepackaged app to ${appPackageTempDir} successfully!`);
        // copy license from root dir to outDir
        const licenseSrc = (0, path_2.join)(path_1.PathUtils.getRootDir(), "LICENSE");
        const licenseDest = (0, path_2.join)(appPackageTempDir, "LICENSE");
        if (await file_1.FileUtils.exists(licenseSrc)) {
            (0, fs_1.cpSync)(licenseSrc, licenseDest);
            logger.debug("Copied LICENSE to packaged app");
        }
    }
    else if ((0, os_1.platform)() === "darwin") {
        await (0, fs_extra_1.ensureDir)(appPackageTempDir);
        // on macOS copy the app bundle only
        const source = path_1.PathUtils.getIOCDAppBundlePath();
        const destination = (0, path_2.join)(appPackageTempDir, config_service_1.ConfigManager.config.mac.appBundleName);
        //const destination = join(appPackageTempDir, ConfigManager.config.productSlug + ".app");
        logger.debug(`Copying prepackaged app bundle from ${source} to ${destination}`);
        (0, child_process_1.execSync)(`ditto "${source}" "${destination}"`, { stdio: "pipe" });
        logger.debug(`Copied prepackaged app to ${appPackageTempDir} successfully!`);
    }
    return appPackageTempDir;
}
/**
 * This function signs the build artifacts produced by the make process.
 * @param makeResults The results of the make process, containing the artifacts to sign.
 */
async function signArtifacts(makeResults) {
    if ((0, os_1.platform)() === "win32") {
        logger.debug("Signing build files");
        const signBinary = (await import("./windows.helper.js")).signBinary;
        // Sign all produced build artifacts BEFORE publishing
        for (const result of makeResults) {
            for (const artifact of result.artifacts) {
                // artifact is a full path to e.g. Setup.exe / .msi / .dmg / .zip
                await signBinary(artifact);
            }
        }
        logger.debug("Signed build files successfully!");
    }
    else if ((0, os_1.platform)() === "darwin") {
        // No need to do anything here, as signing is done during the make process for macOS
    }
}
/** Helper function to find forge.config.js in config directory */
function getForgeConfigPath() {
    const configPath = path_1.PathUtils.getForgeConfigPath();
    if ((0, fs_extra_1.existsSync)(configPath)) {
        return configPath;
    }
    return null;
}
/** Reads the target configurations from the forge.config.js file and enhances it with additional information */
function getTargetsFromConfig() {
    const forgeConfigPath = getForgeConfigPath();
    let overrideTargets = [];
    if (!forgeConfigPath) {
        return overrideTargets;
    }
    const forgeConfig = require(forgeConfigPath);
    if (!forgeConfig.makers || forgeConfig.makers.length === 0) {
        return overrideTargets;
    }
    overrideTargets = forgeConfig.makers.map((t) => {
        const config = config_service_1.ConfigManager.config;
        if (t.name === "@electron-forge/maker-squirrel") {
            const ioAssetsDir = path_1.PathUtils.getIOCDAssetsDir();
            const icon = (0, path_2.join)(ioAssetsDir, "images", "logo.ico");
            const setupExeName = `${(0, path_2.basename)(config.win.exe.exeName).replace(".exe", "")}-v${config.version}-setup.exe`;
            return {
                name: "@electron-forge/maker-squirrel",
                config: {
                    // iconUrl: icon, // needs to be HTTPs; displayed in Control Panel ➡ Programs and Features.
                    exe: config.win.exe.exeName, // * The name of your app's main `.exe` file.
                    // keep this concise
                    setupIcon: icon,
                    setupExe: setupExeName,
                    version: config.version,
                    // Optional: ensure Squirrel uses your short product name
                    name: config.productSlug, // used for package IDs
                    productName: config.productName, // The app name with spaces (will be shown to your users) - https://www.electronforge.io/config/makers/squirrel.windows#spaces-in-the-app-name
                    authors: config.company, //  The `authors` value for the NuGet package metadata.
                    owners: config.company, //  The `owners` value for the NuGet package metadata.
                    copyRight: config.copyright, //  The `copyright` value for the NuGet package metadata.
                    title: config.productName, // used as install window title
                    description: config.productDescription, // used in Control Panel ➡ Programs and Features.
                    noMSI: true,
                    ...(t.config ?? {}),
                    // Keep the nuspect template
                    nuspecTemplate: (0, find_package_dir_1.getCliAssetPath)("win-build/template.nuspectemplate"),
                    usePackageJson: false,
                },
            };
        }
        if (t.name === "@electron-forge/maker-dmg") {
            const ioAssetsDir = path_1.PathUtils.getIOCDAssetsDir();
            let icon = (0, path_2.join)(ioAssetsDir, "images", "logo.icns");
            return {
                name: "@electron-forge/maker-dmg",
                config: {
                    name: `${config.productName}-v${config.version}`,
                    icon: icon,
                    overwrite: true,
                    title: `${config.productName}`,
                    ...(t.config ?? {}),
                },
            };
        }
        return t;
    });
    return overrideTargets;
}
function getPublishersFromConfig() {
    const forgeConfigPath = getForgeConfigPath();
    let overrideTargets = [];
    if (!forgeConfigPath) {
        return overrideTargets;
    }
    const forgeConfig = require(forgeConfigPath);
    if (!forgeConfig.publishers || forgeConfig.publishers.length === 0) {
        return overrideTargets;
    }
    overrideTargets = forgeConfig.publishers.map((t) => {
        return t;
    });
    return overrideTargets;
}
async function ensureElectronVersionIsSet() {
    const electronVersion = await getElectronVersionFromComponent();
    if (!electronVersion) {
        throw new Error("Electron version not found in iocd component metadata");
    }
    logger.debug(`Using Electron version: ${electronVersion}`);
}
/** Reads the electron version from the iocd component metadata */
async function getElectronVersionFromComponent() {
    try {
        const resourcesDir = path_1.PathUtils.getIOCDResourcesDir();
        const metadataPath = (0, path_2.join)(resourcesDir, "metadata.json");
        if (!(await file_1.FileUtils.exists(metadataPath))) {
            logger.debug("No iocd component metadata found, skipping electron version detection");
            return null;
        }
        const metadata = await (0, fs_extra_1.readJson)(metadataPath);
        if (metadata && metadata.electronVersion) {
            return metadata.electronVersion;
        }
        logger.debug("No electron version found in iocd component metadata");
        return null;
    }
    catch (error) {
        logger.debug(`Failed to read electron version from component: ${error instanceof Error ? error.message : String(error)}`);
        return null;
    }
}
//# sourceMappingURL=electronForge.js.map