"use strict";
/**
 * By convention, exit codes in this base class are below 100
 */
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const command_1 = tslib_1.__importDefault(require("@oclif/command"));
const fs_1 = require("fs");
const path_1 = tslib_1.__importDefault(require("path"));
const json_parse_better_errors_1 = tslib_1.__importDefault(require("json-parse-better-errors"));
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
class JBrowseCommand extends command_1.default {
    async init() { }
    async readFile(location) {
        return fs_1.promises.readFile(location, { encoding: 'utf8' });
    }
    async readJsonFile(location) {
        let contents;
        try {
            contents = await fs_1.promises.readFile(location, { encoding: 'utf8' });
        }
        catch (error) {
            this.error(error instanceof Error ? error : `${error}`, {
                suggestions: [
                    `Make sure the file "${location}" exists or use --out to point to a directory with a config.json`,
                    'Run `jbrowse add-assembly` to create a config file',
                ],
                exit: 40,
            });
        }
        let result;
        try {
            result = (0, json_parse_better_errors_1.default)(contents);
        }
        catch (error) {
            this.error(error instanceof Error ? error : `${error}`, {
                suggestions: [`Make sure "${location}" is a valid JSON file`],
                exit: 50,
            });
        }
        return result;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    async writeJsonFile(location, contents) {
        this.debug(`Writing JSON file to ${process.cwd()} ${location}`);
        return fs_1.promises.writeFile(location, JSON.stringify(contents, null, 2));
    }
    async resolveFileLocation(location, check = true, inPlace = false) {
        let locationUrl;
        try {
            locationUrl = new URL(location);
        }
        catch (error) {
            // ignore
        }
        if (locationUrl) {
            if (check) {
                const response = await (0, node_fetch_1.default)(locationUrl, { method: 'HEAD' });
                if (!response.ok) {
                    throw new Error(`${locationUrl} result ${response.statusText}`);
                }
            }
            return locationUrl.href;
        }
        let locationPath;
        try {
            if (check) {
                locationPath = await fs_1.promises.realpath(location);
            }
            else {
                locationPath = location;
            }
        }
        catch (e) {
            // ignore
        }
        if (locationPath) {
            const filePath = path_1.default.relative(process.cwd(), locationPath);
            if (inPlace && filePath.startsWith('..')) {
                this.warn(`Location ${filePath} is not in the JBrowse directory. Make sure it is still in your server directory.`);
            }
            return inPlace ? location : filePath;
        }
        return this.error(`Could not resolve to a file or a URL: "${location}"`, {
            exit: 40,
        });
    }
    async readInlineOrFileJson(inlineOrFileName) {
        let result;
        // see if it's inline JSON
        try {
            result = (0, json_parse_better_errors_1.default)(inlineOrFileName);
        }
        catch (error) {
            this.debug(`Not valid inline JSON, attempting to parse as filename: '${inlineOrFileName}'`);
            // not inline JSON, must be location of a JSON file
            result = await this.readJsonFile(inlineOrFileName);
        }
        return result;
    }
    async fetchGithubVersions() {
        var e_1, _a;
        let versions = [];
        try {
            for (var _b = tslib_1.__asyncValues(this.fetchVersions()), _c; _c = await _b.next(), !_c.done;) {
                const iter = _c.value;
                versions = versions.concat(iter);
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_c && !_c.done && (_a = _b.return)) await _a.call(_b);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return versions;
    }
    async getLatest() {
        var e_2, _a;
        var _b;
        try {
            for (var _c = tslib_1.__asyncValues(this.fetchVersions()), _d; _d = await _c.next(), !_d.done;) {
                const versions = _d.value;
                // if a release was just uploaded, or an erroneous build was made
                // then it might have no build asset
                const nonprereleases = versions
                    .filter(release => release.prerelease === false)
                    .filter(release => release.assets && release.assets.length > 0);
                if (nonprereleases.length !== 0) {
                    // @ts-ignore
                    const file = (_b = nonprereleases[0].assets.find(f => f.name.includes('jbrowse-web'))) === null || _b === void 0 ? void 0 : _b.browser_download_url;
                    if (!file) {
                        throw new Error('no jbrowse-web download found');
                    }
                    return file;
                }
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (_d && !_d.done && (_a = _c.return)) await _a.call(_c);
            }
            finally { if (e_2) throw e_2.error; }
        }
        throw new Error('no version tags found');
    }
    fetchVersions() {
        return tslib_1.__asyncGenerator(this, arguments, function* fetchVersions_1() {
            let page = 1;
            let result;
            do {
                const response = yield tslib_1.__await((0, node_fetch_1.default)(`https://api.github.com/repos/GMOD/jbrowse-components/releases?page=${page}`));
                if (response.ok) {
                    result = (yield tslib_1.__await(response.json()));
                    yield yield tslib_1.__await(result.filter(release => release.tag_name.startsWith('v')));
                    page++;
                }
                else {
                    throw new Error(`${response.statusText}`);
                }
            } while (result && result.length > 0);
        });
    }
    async getTag(tag) {
        var _a, _b;
        const response = await (0, node_fetch_1.default)(`https://api.github.com/repos/GMOD/jbrowse-components/releases/tags/${tag}`);
        if (response.ok) {
            const result = (await response.json());
            const file = (_b = (_a = result === null || result === void 0 ? void 0 : result.assets) === null || _a === void 0 ? void 0 : _a.find(f => f.name.includes('jbrowse-web'))) === null || _b === void 0 ? void 0 : _b.browser_download_url;
            if (!file) {
                this.error('Could not find version specified. Use --listVersions to see all available versions', { exit: 90 });
            }
            return file;
        }
        return this.error(`Could not find version: ${response.statusText}`, {
            exit: 90,
        });
    }
    async getBranch(branch) {
        return `https://s3.amazonaws.com/jbrowse.org/code/jb2/${branch}/jbrowse-web-${branch}.zip`;
    }
}
exports.default = JBrowseCommand;
