"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "ClientBundleService", {
    enumerable: true,
    get: function() {
        return ClientBundleService;
    }
});
const _admzip = /*#__PURE__*/ _interop_require_default(require("adm-zip"));
const _path = require("path");
const _nodefs = require("node:fs");
const _promises = require("node:fs/promises");
const _fsutils = require("../../utils/fs.utils");
const _semverutils = require("../../utils/semver.utils");
const _serverconstants = require("../../server.constants");
const _semver = require("semver");
const _errorutils = require("../../utils/error.utils");
const _runtimeexceptions = require("../../exceptions/runtime.exceptions");
const _octokit = require("octokit");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
class ClientBundleService {
    githubService;
    configService;
    logger;
    constructor({ githubService, configService, loggerFactory }){
        this.githubService = githubService;
        this.configService = configService;
        this.logger = loggerFactory(ClientBundleService.name);
    }
    get clientPackageJsonPath() {
        return (0, _path.join)((0, _fsutils.superRootPath)(), _serverconstants.AppConstants.defaultClientBundleStorage, "package.json");
    }
    get clientIndexHtmlPath() {
        return (0, _path.join)((0, _fsutils.superRootPath)(), _serverconstants.AppConstants.defaultClientBundleStorage, "dist/index.html");
    }
    async getReleases() {
        const githubOwner = _serverconstants.AppConstants.orgName;
        const githubRepo = _serverconstants.AppConstants.clientRepoName;
        try {
            const result = await this.githubService.getReleases(githubOwner, githubRepo);
            const latestResult = await this.githubService.getLatestRelease(githubOwner, githubRepo);
            return {
                minimum: {
                    tag_name: _serverconstants.AppConstants.defaultClientMinimum
                },
                current: {
                    tag_name: this.getClientVersion()
                },
                latest: latestResult.data,
                releases: result.data
            };
        } catch (e) {
            if (e instanceof _octokit.RequestError) {
                this.logger.error(`Github OctoKit error ${(0, _errorutils.errorSummary)(e)}`);
                throw new _runtimeexceptions.ExternalServiceError({
                    error: "Github OctoKit error: " + e.message
                }, "GitHub");
            }
            throw new _runtimeexceptions.InternalServerException("Something went wrong with the request to Github");
        }
    }
    async shouldUpdateWithReason(overrideAutoUpdate, minimumVersion, requestedVersion, allowDowngrade) {
        const clientAutoUpdate = _serverconstants.AppConstants.enableClientDistAutoUpdateKey;
        const existingClientVersion = this.getClientVersion();
        if (!clientAutoUpdate && !overrideAutoUpdate) {
            return {
                shouldUpdate: false,
                requestedVersion,
                minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                currentVersion: existingClientVersion,
                targetVersion: null,
                reason: "Client auto-update disabled (ENABLE_CLIENT_DIST_AUTO_UPDATE), skipping"
            };
        }
        if (!existingClientVersion) {
            return {
                shouldUpdate: true,
                requestedVersion,
                currentVersion: existingClientVersion,
                minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                targetVersion: (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion),
                reason: `Client package.json does not exist, downloading new release`
            };
        }
        if (!this.doesClientIndexHtmlExist()) {
            return {
                shouldUpdate: true,
                requestedVersion,
                currentVersion: existingClientVersion,
                minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                targetVersion: (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion),
                reason: `Client index.html could not be found, downloading new release`
            };
        }
        const satisfiesMinimumVersion = (0, _semverutils.checkVersionSatisfiesMinimum)(existingClientVersion, minimumVersion);
        const clientOutdated = !satisfiesMinimumVersion;
        const clientOutdatedResponse = {
            shouldUpdate: true,
            requestedVersion,
            currentVersion: existingClientVersion,
            minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
            targetVersion: (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion),
            reason: `Client bundle release ${existingClientVersion} does not satisfy minimum version ${minimumVersion}, downloading new release`
        };
        if (!!requestedVersion) {
            const minimumComparison = (0, _semver.compare)(requestedVersion, minimumVersion);
            if (minimumComparison === -1) {
                if (clientOutdated) return clientOutdatedResponse;
                return {
                    shouldUpdate: false,
                    requestedVersion,
                    currentVersion: existingClientVersion,
                    minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                    targetVersion: requestedVersion,
                    reason: `Requested version ${requestedVersion} is below minimum designed version ${minimumVersion}, skipping`
                };
            }
            const newComparison = (0, _semver.compare)(requestedVersion, existingClientVersion);
            const isDowngrade = newComparison === -1;
            if (isDowngrade) {
                if (!allowDowngrade && clientOutdated) return clientOutdatedResponse;
                return {
                    shouldUpdate: allowDowngrade,
                    requestedVersion,
                    currentVersion: existingClientVersion,
                    minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                    targetVersion: requestedVersion,
                    reason: allowDowngrade ? `Client bundle downgrade allowed (above ${minimumVersion}), downloading new release` : `Client bundle downgrade not allowed (even thought above ${minimumVersion}), skipping`
                };
            } else if (newComparison === 1) {
                return {
                    shouldUpdate: true,
                    requestedVersion,
                    currentVersion: existingClientVersion,
                    minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
                    targetVersion: (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion),
                    reason: `Client bundle release ${requestedVersion} is above existing version ${existingClientVersion}, downloading updated release`
                };
            }
        }
        if (!satisfiesMinimumVersion) {
            return clientOutdatedResponse;
        }
        return {
            shouldUpdate: false,
            requestedVersion,
            currentVersion: existingClientVersion,
            minimumVersion: _serverconstants.AppConstants.defaultClientMinimum,
            targetVersion: (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion),
            reason: `Client already satisfies minimum version ${minimumVersion} and requested version is not an upgrade, skipping`
        };
    }
    async downloadClientUpdate(releaseTag) {
        const release = await this.getClientBundleRelease(releaseTag);
        this.logger.log(`Retrieved ${release.assets.length} assets from release '${release.name}': ${release.assets.map((a)=>a.name)}`);
        const assetName = `dist-client-${release.tag_name}.zip`;
        const asset = release.assets.find((a)=>a.name === assetName);
        if (!asset) {
            throw new _runtimeexceptions.NotFoundException(`Release with tag ${release.tag_name} asset ${assetName} does not exist`);
        }
        const assetId = asset?.id;
        const downloadPath = await this.downloadClientBundleZip(assetId, asset.name);
        await this.extractClientBundleZip(downloadPath);
        return release.tag_name;
    }
    async getClientBundleRelease(releaseTag) {
        const githubOwner = _serverconstants.AppConstants.orgName;
        const githubRepo = _serverconstants.AppConstants.clientRepoName;
        const result = await this.githubService.getReleaseByTag(githubOwner, githubRepo, releaseTag);
        return result.data;
    }
    async downloadClientBundleZip(assetId, assetName) {
        const githubOwner = _serverconstants.AppConstants.orgName;
        const githubRepo = _serverconstants.AppConstants.clientRepoName;
        const assetResult = await this.githubService.requestAsset(githubOwner, githubRepo, assetId);
        const dir = (0, _path.join)((0, _fsutils.superRootPath)(), _serverconstants.AppConstants.defaultClientBundleZipsStorage);
        (0, _fsutils.ensureDirExists)(dir);
        this.logger.log(`Downloaded client release ZIP to '${dir}'. Extracting archive now`);
        const path = (0, _path.join)(dir, assetName);
        (0, _nodefs.writeFileSync)(path, Buffer.from(assetResult.data));
        return path;
    }
    async extractClientBundleZip(downloadedZipPath) {
        const distPath = (0, _path.join)((0, _fsutils.superRootPath)(), _serverconstants.AppConstants.defaultClientBundleStorage);
        const zip = new _admzip.default(downloadedZipPath);
        (0, _fsutils.ensureDirExists)(distPath);
        this.logger.debug(`Clearing contents of ${distPath}`);
        for (const fileOrDir of (await (0, _promises.readdir)(distPath))){
            this.logger.log(`Removing existing file/dir '${distPath}/${fileOrDir}' before updating client`);
            try {
                await (0, _promises.rm)((0, _path.join)(distPath, fileOrDir), {
                    force: true,
                    recursive: true
                });
            } catch (e) {
                this.logger.error(`${e.message} ${e.stack}`);
                throw e;
            }
        }
        try {
            zip.extractAllTo((0, _path.join)((0, _fsutils.superRootPath)(), _serverconstants.AppConstants.defaultClientBundleStorage));
        } catch (e) {
            this.logger.error(`Unzipping failed ${e.message} ${e.stack}`);
            throw e;
        }
        this.logger.log(`Successfully extracted client dist to ${distPath}`);
    }
    doesClientIndexHtmlExist() {
        const indexHtmlPath = this.clientIndexHtmlPath;
        return (0, _nodefs.existsSync)(indexHtmlPath);
    }
    getClientVersion() {
        const packageJsonPath = this.clientPackageJsonPath;
        const packageJsonFound = (0, _nodefs.existsSync)(packageJsonPath);
        if (!packageJsonFound) {
            return;
        }
        require.cache[packageJsonPath] = undefined;
        const json = require(packageJsonPath);
        return json?.version;
    }
}

//# sourceMappingURL=client-bundle.service.js.map