"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 _nodepath = require("node: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;
    logger;
    githubOwner = _serverconstants.AppConstants.orgName;
    githubRepo = _serverconstants.AppConstants.clientRepoName;
    minVersion = _serverconstants.AppConstants.defaultClientMinimum;
    constructor(loggerFactory, githubService){
        this.githubService = githubService;
        this.logger = loggerFactory(ClientBundleService.name);
    }
    get clientPackageJsonPath() {
        return (0, _nodepath.join)((0, _fsutils.getMediaPath)(), _serverconstants.AppConstants.defaultClientBundleStorage, "package.json");
    }
    get clientIndexHtmlPath() {
        return (0, _nodepath.join)((0, _fsutils.getMediaPath)(), _serverconstants.AppConstants.defaultClientBundleStorage, "dist/index.html");
    }
    async getReleases() {
        try {
            const [releases, latestRelease] = await Promise.all([
                this.githubService.getReleases(this.githubOwner, this.githubRepo),
                this.githubService.getLatestRelease(this.githubOwner, this.githubRepo)
            ]);
            return {
                minimum: {
                    tag_name: this.minVersion
                },
                current: {
                    tag_name: this.getClientVersion()
                },
                latest: latestRelease.data,
                releases: releases.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 existingVersion = this.getClientVersion();
        minimumVersion ??= this.minVersion;
        if (!clientAutoUpdate && !overrideAutoUpdate) {
            return this.createResponse(false, existingVersion, minimumVersion, requestedVersion, null, "Client auto-update disabled, skipping");
        }
        if (!existingVersion || !this.doesClientIndexHtmlExist()) {
            const reason = existingVersion ? "Client index.html could not be found" : "Client package.json does not exist";
            return this.createResponse(true, existingVersion, minimumVersion, requestedVersion, (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion), `${reason}, downloading new release`);
        }
        const meetsMinimum = (0, _semverutils.checkVersionSatisfiesMinimum)(existingVersion, minimumVersion);
        if (!meetsMinimum) {
            return this.createResponse(true, existingVersion, minimumVersion, requestedVersion, (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion), `Client version ${existingVersion} below minimum ${minimumVersion}, downloading new release`);
        }
        if (requestedVersion) {
            return this.evaluateRequestedVersion(existingVersion, minimumVersion, requestedVersion, allowDowngrade);
        }
        return this.createResponse(false, existingVersion, minimumVersion, requestedVersion, (0, _semverutils.getMaximumOfVersionsSafe)(minimumVersion, requestedVersion), `Client already satisfies minimum version ${minimumVersion}`);
    }
    async downloadClientUpdate(releaseTag) {
        const result = await this.githubService.getReleaseByTag(this.githubOwner, this.githubRepo, releaseTag);
        const release = result.data;
        const assetName = `dist-client-${release.tag_name}.zip`;
        const asset = release.assets.find((a)=>a.name === assetName);
        if (!asset) {
            throw new _runtimeexceptions.NotFoundException(`Asset ${assetName} not found in release ${release.tag_name}`);
        }
        const zipPath = await this.downloadZip(asset.id, asset.name);
        await this.extractZip(zipPath);
        return release.tag_name;
    }
    evaluateRequestedVersion(currentVersion, minimumVersion, requestedVersion, allowDowngrade) {
        if ((0, _semver.compare)(requestedVersion, minimumVersion) === -1) {
            return this.createResponse(false, currentVersion, minimumVersion, requestedVersion, requestedVersion, `Requested version ${requestedVersion} below minimum ${minimumVersion}, skipping`);
        }
        const versionComparison = (0, _semver.compare)(requestedVersion, currentVersion);
        if (versionComparison === 0) {
            return this.createResponse(false, currentVersion, minimumVersion, requestedVersion, requestedVersion, `Requested version ${requestedVersion} same as current, skipping`);
        } else if (versionComparison === -1) {
            return this.createResponse(!!allowDowngrade, currentVersion, minimumVersion, requestedVersion, requestedVersion, allowDowngrade ? `Downgrading to ${requestedVersion} (above minimum ${minimumVersion})` : `Downgrade not allowed, skipping`);
        } else {
            return this.createResponse(true, currentVersion, minimumVersion, requestedVersion, requestedVersion, `Upgrading from ${currentVersion} to ${requestedVersion}`);
        }
    }
    createResponse(shouldUpdate, currentVersion, minimumVersion, requestedVersion, targetVersion, reason) {
        return {
            shouldUpdate,
            requestedVersion,
            currentVersion,
            minimumVersion,
            targetVersion,
            reason
        };
    }
    async downloadZip(assetId, assetName) {
        const assetResult = await this.githubService.requestAsset(this.githubOwner, this.githubRepo, assetId);
        const distZipPath = (0, _nodepath.join)((0, _fsutils.getMediaPath)(), _serverconstants.AppConstants.defaultClientBundleZipsStorage);
        (0, _fsutils.ensureDirExists)(distZipPath);
        const path = (0, _nodepath.join)(distZipPath, assetName);
        (0, _nodefs.writeFileSync)(path, Buffer.from(assetResult.data));
        this.logger.log(`Downloaded client ZIP to ${distZipPath}`);
        return path;
    }
    async extractZip(zipPath) {
        const distPath = (0, _nodepath.join)((0, _fsutils.getMediaPath)(), _serverconstants.AppConstants.defaultClientBundleStorage);
        (0, _fsutils.ensureDirExists)(distPath);
        this.logger.debug(`Clearing contents of ${distPath}`);
        for (const item of (await (0, _promises.readdir)(distPath))){
            const itemPath = (0, _nodepath.join)(distPath, item);
            await (0, _promises.rm)(itemPath, {
                force: true,
                recursive: true
            }).catch((e)=>this.logger.error(`Failed to remove ${itemPath}: ${e.message}`));
        }
        try {
            const zip = new _admzip.default(zipPath);
            zip.extractAllTo(distPath);
            this.logger.log(`Successfully extracted client to ${distPath}`);
        } catch (e) {
            this.logger.error(`Extraction failed: ${e.message}`);
            throw e;
        }
    }
    doesClientIndexHtmlExist() {
        return (0, _nodefs.existsSync)(this.clientIndexHtmlPath);
    }
    getClientVersion() {
        const path = this.clientPackageJsonPath;
        if (!(0, _nodefs.existsSync)(path)) {
            return null;
        }
        require.cache[path] = undefined;
        const json = require(path);
        return json?.version ?? null;
    }
}

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