// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT

import fs from 'fs-extra';
import semver from 'semver';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

const packageType = 'module';
const repositoryOwner = process.env.CI_REPO_OWNER;
const repositoryName = process.env.CI_REPO_NAME;
const repositoryURL = process.env.CI_REPO_LINK;
const forgeURL = process.env.CI_FORGE_URL;

const getManifestUrl = (channel) =>
  `${forgeURL}/api/packages/${repositoryOwner}/generic/${repositoryName}/${channel}/${packageType}.json`;
const getDownloadURL = (version) => `${repositoryURL}/releases/download/${version}/${repositoryName}.zip`;
const bugsURL = `${repositoryURL}/issues`;
const getChangelogURL = (version) => `${repositoryURL}/releases/tag/${version}`;
const getReadmeURL = (version) => `${repositoryURL}/raw/tag/${version}/README.md`;
const getLicenseURL = (version) => `${repositoryURL}/raw/tag/${version}/LICENSE.md`;

const manifestPath = `${packageType}.json`;

/**
 * Get the contents of the manifest file as object.
 * @returns {unknown} An object describing the manifest
 */
function getManifest() {
  if (fs.existsSync(manifestPath)) {
    return fs.readJSONSync(manifestPath);
  }
}

/**
 * Get the target version based on on the current version and the argument passed as release.
 * @param {string} currentVersion The current version
 * @param {semver.ReleaseType | string} release Either a semver release type or a valid semver version
 * @returns {string | null} The target version
 */
function getTargetVersion(currentVersion, release) {
  if (['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].includes(release)) {
    return semver.inc(currentVersion, release);
  } else {
    return semver.valid(release);
  }
}

/**
 * Get the channel for a given version.
 * @param {string} version The version for which to get the channel
 * @returns {"latest" | "beta"} The channel for the version
 */
function getChannel(version) {
  return version.includes('-') ? 'beta' : 'latest';
}

/**
 * Update version and download URL.
 * @param {semver.ReleaseType | string} release Either a semver release type or a valid semver version
 */
function bumpVersion(release) {
  if (!release) {
    throw new Error('Missing release type');
  }

  const packageJson = fs.readJSONSync('package.json');
  const manifest = getManifest();
  if (!manifest) throw new Error('Manifest JSON not found');

  const currentVersion = packageJson.version;
  const targetVersion = getTargetVersion(currentVersion, release);

  if (!targetVersion) {
    throw new Error('Incorrect version arguments');
  }
  if (targetVersion === currentVersion) {
    throw new Error('Target version is identical to current version');
  }

  console.log(`Bumping version number to '${targetVersion}'`);
  packageJson.version = targetVersion;
  fs.writeJSONSync('package.json', packageJson, { spaces: 2 });
  manifest.version = targetVersion;
  manifest.url = repositoryURL;
  manifest.manifest = getManifestUrl(getChannel(targetVersion));
  manifest.download = getDownloadURL(targetVersion);
  manifest.bugs = bugsURL;
  manifest.changelog = getChangelogURL(targetVersion);
  manifest.readme = getReadmeURL(targetVersion);
  manifest.license = getLicenseURL(targetVersion);
  fs.writeJSONSync(manifestPath, manifest, { spaces: 2 });
}

const argv = yargs(hideBin(process.argv)).usage('Usage: $0').option('release', {
  alias: 'r',
  type: 'string',
  demandOption: true,
  description: 'Either a semver release type or a valid semver version',
}).argv;
const release = argv.r;
bumpVersion(release);
