"use strict";
/**
 * By convention, exit codes in this base class are below 100
 */
var __asyncValues = (this && this.__asyncValues) || function (o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var g = generator.apply(thisArg, _arguments || []), i, q = [];
    return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
    function fulfill(value) { resume("next", value); }
    function reject(value) { resume("throw", value); }
    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const command_1 = __importDefault(require("@oclif/command"));
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const json_parse_better_errors_1 = __importDefault(require("json-parse-better-errors"));
const fetchWithProxy_1 = __importDefault(require("./fetchWithProxy"));
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, fetchWithProxy_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 _a, e_1, _b, _c;
        let versions = [];
        try {
            for (var _d = true, _e = __asyncValues(this.fetchVersions()), _f; _f = await _e.next(), _a = _f.done, !_a;) {
                _c = _f.value;
                _d = false;
                try {
                    const iter = _c;
                    versions = versions.concat(iter);
                }
                finally {
                    _d = true;
                }
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return versions;
    }
    async getLatest() {
        var _a, e_2, _b, _c;
        var _d;
        try {
            for (var _e = true, _f = __asyncValues(this.fetchVersions()), _g; _g = await _f.next(), _a = _g.done, !_a;) {
                _c = _g.value;
                _e = false;
                try {
                    const versions = _c;
                    // 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 = (_d = nonprereleases[0].assets.find(f => f.name.includes('jbrowse-web'))) === null || _d === void 0 ? void 0 : _d.browser_download_url;
                        if (!file) {
                            throw new Error('no jbrowse-web download found');
                        }
                        return file;
                    }
                }
                finally {
                    _e = true;
                }
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (!_e && !_a && (_b = _f.return)) await _b.call(_f);
            }
            finally { if (e_2) throw e_2.error; }
        }
        throw new Error('no version tags found');
    }
    fetchVersions() {
        return __asyncGenerator(this, arguments, function* fetchVersions_1() {
            let page = 1;
            let result;
            do {
                const response = yield __await((0, fetchWithProxy_1.default)(`https://api.github.com/repos/GMOD/jbrowse-components/releases?page=${page}`));
                if (response.ok) {
                    result = (yield __await(response.json()));
                    yield yield __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, fetchWithProxy_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;
