"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.debug = debug;
exports.readFile = readFile;
exports.readJsonFile = readJsonFile;
exports.writeJsonFile = writeJsonFile;
exports.resolveFileLocation = resolveFileLocation;
exports.readInlineOrFileJson = readInlineOrFileJson;
exports.fetchGithubVersions = fetchGithubVersions;
exports.getLatest = getLatest;
exports.fetchVersions = fetchVersions;
exports.getTag = getTag;
exports.getBranch = getBranch;
exports.printHelp = printHelp;
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"));
function debug(message) {
    if (process.env.DEBUG) {
        console.log(`DEBUG: ${message}`);
    }
}
async function readFile(location) {
    return fs_1.promises.readFile(location, { encoding: 'utf8' });
}
async function readJsonFile(location) {
    const contents = await fs_1.promises.readFile(location, { encoding: 'utf8' });
    return (0, json_parse_better_errors_1.default)(contents);
}
async function writeJsonFile(location, contents) {
    debug(`Writing JSON file to ${process.cwd()} ${location}`);
    return fs_1.promises.writeFile(location, JSON.stringify(contents, null, 2));
}
async function resolveFileLocation(location, check = true, inPlace = false) {
    let locationUrl;
    try {
        locationUrl = new URL(location);
    }
    catch (error) {
        // ignore
    }
    if (locationUrl) {
        if (check) {
            // @ts-expect-error
            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 {
        locationPath = check ? await fs_1.promises.realpath(location) : location;
    }
    catch (e) {
        // ignore
    }
    if (locationPath) {
        const filePath = path_1.default.relative(process.cwd(), locationPath);
        if (inPlace && filePath.startsWith('..')) {
            console.warn(`Location ${filePath} is not in the JBrowse directory. Make sure it is still in your server directory.`);
        }
        return inPlace ? location : filePath;
    }
    throw new Error(`Could not resolve to a file or a URL: "${location}"`);
}
async function readInlineOrFileJson(inlineOrFileName) {
    let result;
    // see if it's inline JSON
    try {
        result = (0, json_parse_better_errors_1.default)(inlineOrFileName);
    }
    catch (error) {
        debug(`Not valid inline JSON, attempting to parse as filename: '${inlineOrFileName}'`);
        // not inline JSON, must be location of a JSON file
        result = await readJsonFile(inlineOrFileName);
    }
    return result;
}
async function fetchGithubVersions() {
    let versions = [];
    for await (const iter of fetchVersions()) {
        versions = [...versions, ...iter];
    }
    return versions;
}
async function getLatest() {
    for await (const versions of fetchVersions()) {
        // 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)
            .filter(release => release.assets?.length);
        if (nonprereleases.length > 0) {
            // @ts-expect-error
            const file = nonprereleases[0].assets.find(f => f.name.includes('jbrowse-web'))?.browser_download_url;
            if (!file) {
                throw new Error('no jbrowse-web download found');
            }
            return file;
        }
    }
    throw new Error('no version tags found');
}
async function* fetchVersions() {
    let page = 1;
    let result;
    do {
        const url = `https://api.github.com/repos/GMOD/jbrowse-components/releases?page=${page}`;
        const response = await (0, fetchWithProxy_1.default)(url);
        if (response.ok) {
            result = (await response.json());
            yield result.filter(release => release.tag_name.startsWith('v'));
            page++;
        }
        else {
            throw new Error(`HTTP ${response.status} fetching ${url}`);
        }
    } while (result.length);
}
async function getTag(tag) {
    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 = result.assets?.find(f => f.name.includes('jbrowse-web'))?.browser_download_url;
        if (!file) {
            throw new Error('Could not find version specified. Use --listVersions to see all available versions');
        }
        return file;
    }
    throw new Error(`Could not find version: ${response.statusText}`);
}
async function getBranch(branch) {
    return `https://s3.amazonaws.com/jbrowse.org/code/jb2/${branch}/jbrowse-web-${branch}.zip`;
}
function printHelp({ description, options, examples, usage, }) {
    console.log(description);
    console.log(`\nUsage: ${usage || 'jbrowse <command> [options]'}`);
    console.log('\nOptions:');
    for (const [name, option] of Object.entries(options)) {
        const short = 'short' in option && option.short
            ? `-${option.short}`
            : '   ';
        const namePadded = `--${name}`.padEnd(25, ' ');
        const desc = option.description?.replace(/\n/g, `\n${' '.repeat(29)}`);
        console.log(`  ${short}, ${namePadded} ${desc}`);
    }
    console.log(`\n${examples.join('\n')}`);
}
