/* eslint-disable import/default */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ux } from "@oclif/core";
import decompress from "decompress";
import fs from "fs-extra/esm";
import log4js from "log4js";
import { existsSync } from "node:fs";
import { copyFile, mkdir, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { PLATFORM_TEMPLATE, TEMP_ZIP_NAME } from "../../shared/constants.js";
import { obfuscateLicense } from "../../utils/license-obfuscate.js";
import locatorService from "../locator.service.js";
export class BrowserPlatformService {
    currentDir = process.cwd();
    logger = log4js.getLogger("NewBrowserPlatformService");
    async build(config) {
        const { appName, template, version } = config;
        this.logger.info(`Creating new ${appName} app with io.CB version ${version} and template ${template}`);
        ux.info(`Creating new ${appName} app with io.CB version ${version} and template ${template}`);
        const cliConfig = await locatorService.configurationService.getCliConfig();
        const appDir = join(this.currentDir, appName);
        this.logger.info(`Making new app directory at ${appDir}`);
        await mkdir(appDir);
        this.logger.info(`New app directory created at ${appDir}, proceeding with fetching ${template} template`);
        const resolvedMode = await this.getZipTemplate(config, cliConfig);
        this.logger.info(`Fetched ${template} template with mode ${resolvedMode}, proceeding with unpacking`);
        ux.info(`Proceeding with ${resolvedMode} template`);
        await this.unpackZipTemplate(appDir, template, join(appDir, TEMP_ZIP_NAME));
        this.logger.info(`Unpacked ${template} template, proceeding with ${template} configuration`);
        if (template === "vanilla-js") {
            await this.configureVanillaJsTemplate(config, cliConfig);
        }
        if (template === "home-react-wsp") {
            await this.configureHomeWspReactTemplate(config, cliConfig);
        }
        if (template === "dev-react-seed") {
            await this.configureDevReactSeedTemplate(config, cliConfig);
        }
        if (template === "wsp-frame") {
            await this.configureWspFrameTemplate(config, cliConfig);
        }
        this.logger.info(`New ${appName} app creation complete.`);
        ux.info(`New Browser Platform Creation Complete. Please run "cd ./${appName}" and "npm install" to install dependencies${template === PLATFORM_TEMPLATE.DEV_REACT_SEED ? `, "npm run bootstrap" to install all dependencies for all apps` : ""} and "npm start" to start the app.`);
    }
    async clean(config) {
        const appDir = join(this.currentDir, config.appName);
        this.logger.info(`Cleaning up the app directory at ${appDir}`);
        await rm(appDir, { force: true, recursive: true });
        ux.action.stop("New Browser Platform Creation Failed. Cleaned up the app directory.");
        this.logger.info(`Cleaned up the app directory at ${appDir}`);
    }
    async configureDevReactSeedTemplate(config, cliConfig) {
        const appDir = join(this.currentDir, config.appName);
        const configExampleLocation = join(appDir, "workspace-platform", "src", "config.example.json");
        const configLocation = join(appDir, "workspace-platform", "src", "config.json");
        await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "dev-react-seed");
    }
    async configureHomeWspReactTemplate(config, cliConfig) {
        const appDir = join(this.currentDir, config.appName);
        const configExampleLocation = join(appDir, "src", "config.example.json");
        const configLocation = join(appDir, "src", "config.json");
        await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "home-react-wsp");
    }
    async configureVanillaJsTemplate(config, cliConfig) {
        const appDir = join(this.currentDir, config.appName);
        const configExampleLocation = join(appDir, "public", "config.example.json");
        const configLocation = join(appDir, "public", "config.json");
        await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "vanilla-js");
    }
    async configureWspFrameTemplate(config, cliConfig) {
        const appDir = join(this.currentDir, config.appName);
        const configExampleLocation = join(appDir, "src", "config.example.json");
        const configLocation = join(appDir, "src", "config.json");
        await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "wsp-frame");
    }
    async getZipTemplate(config, cliConfig) {
        const { appName, version } = config;
        const appDir = join(this.currentDir, appName);
        const zipLocation = join(appDir, TEMP_ZIP_NAME);
        if (cliConfig.mode === "remote") {
            this.logger.info(`Fetching remote template ${version}, to zip location ${zipLocation}`);
            await this.resolveRemoteZip(version, zipLocation);
            this.logger.info(`Completed remote template fetch`);
            return "remote";
        }
        if (cliConfig.mode === "offline") {
            this.logger.info(`Fetching offline template ${version}, to zip location ${zipLocation}`);
            await this.resolveLocalZip(version, zipLocation);
            this.logger.info(`Completed local template fetch`);
            return "offline";
        }
        try {
            this.logger.info(`Fetching remote template ${version}, to zip location ${zipLocation}, with auto mode`);
            await this.resolveRemoteZip(version, zipLocation);
            this.logger.info(`Completed remote template fetch with auto mode`);
            return "remote";
        }
        catch (error) {
            this.logger.warn(`Could not get the remote template, falling back to the offline template. Reason: ${error.message}`);
            ux.warn(`Could not get the remote template, falling back to the offline template. Reason: ${error.message}`);
            await this.resolveLocalZip(version, zipLocation, `Unable to get the remote template, resolved to the offline template ${version}`);
            this.logger.info(`Completed local fallback template fetch with auto mode`);
            return "offline";
        }
    }
    async resolveLocalZip(version, zipLocation, stopMessage) {
        ux.action.start(`Fetching offline template ${version}`);
        const verifiedVersion = await locatorService.validationService.transformVersion(version, "ioCb", "offline");
        const { root } = locatorService.configurationService.directoryConfig;
        const templateLocation = join(root, "templates", verifiedVersion ? `${verifiedVersion}.zip` : "latest.zip");
        existsSync(templateLocation) || ux.error(`Could not find the offline template ${version}`);
        await copyFile(templateLocation, zipLocation);
        ux.action.stop(stopMessage);
    }
    async resolveRemoteZip(version, zipLocation, stopMessage) {
        ux.action.start(`Downloading remote template ${version}`);
        const verifiedVersion = await locatorService.validationService.transformVersion(version, "ioCb", "remote");
        await locatorService.downloaderService.downloadRemoteZip(verifiedVersion, zipLocation);
        ux.action.stop(stopMessage);
    }
    async setPlatformConfig(cliConfig, configExampleLocation, configLocation, template) {
        this.logger.info(`Setting the config.json file with license key ${cliConfig.licenseKey ? obfuscateLicense(cliConfig.licenseKey) : "no license key"}, using example file at ${configExampleLocation}`);
        existsSync(configExampleLocation) || ux.error(`Could not find the config.example.json file at ${configExampleLocation}`);
        const configFile = await fs.readJSON(configExampleLocation, { throws: false });
        if (template === "dev-react-seed" || template === "wsp-frame") {
            configFile.browserPlatform.licenseKey = cliConfig.licenseKey;
        }
        else {
            configFile.licenseKey = cliConfig.licenseKey;
        }
        await writeFile(configLocation, JSON.stringify(configFile, null, 4));
        this.logger.info(`Set the config.json file at location ${configLocation}`);
    }
    async unpackZipTemplate(appDir, template, zipLocation) {
        await mkdir(join(appDir, "temp"));
        await decompress(zipLocation, join(appDir, "temp"), { strip: 1 });
        const source = join(appDir, "temp", `browser-platform-${template}`);
        existsSync(source) || ux.error(`Could not find the template ${join(appDir, "temp", `browser-platform-${template}`)}`);
        fs.copySync(source, appDir, { overwrite: true });
        await rm(zipLocation, { force: true, recursive: true });
        await rm(join(appDir, "temp"), { force: true, recursive: true });
    }
}
