import semver from 'semver';

import asyncHandler from '../utils/asyncHandler.js';
import createPackageURL from '../utils/createPackageURL.js';
import { getPackageConfig, getVersionsAndTags } from '../utils/npm.js';

function semverRedirect(req, res, newVersion) {
  res
    .set({
      'Cache-Control': 'public, s-maxage=600, max-age=60', // 10 mins on CDN, 1 min on clients
      'Cache-Tag': 'redirect, semver-redirect'
    })
    .redirect(
      302,
      req.baseUrl +
        createPackageURL(req.packageName, newVersion, req.filename, req.query)
    );
}

async function resolveVersion(packageName, range, log) {
  const versionsAndTags = await getVersionsAndTags(packageName, log);

  if (versionsAndTags) {
    const { versions, tags } = versionsAndTags;

    if (range in tags) {
      range = tags[range];
    }

    return versions.includes(range)
      ? range
      : semver.maxSatisfying(versions, range);
  }

  return null;
}

/**
 * Check the package version/tag in the URL and make sure it's good. Also
 * fetch the package config and add it to req.packageConfig. Redirect to
 * the resolved version number if necessary.
 */
async function validateVersion(req, res, next) {
  const version = await resolveVersion(
    req.packageName,
    req.packageVersion,
    req.log
  );

  if (!version) {
    return res
      .status(404)
      .type('text')
      .send(`Cannot find package ${req.packageSpec}`);
  }

  if (version !== req.packageVersion) {
    return semverRedirect(req, res, version);
  }

  req.packageConfig = await getPackageConfig(
    req.packageName,
    req.packageVersion,
    req.log
  );

  if (!req.packageConfig) {
    return res
      .status(500)
      .type('text')
      .send(`Cannot get config for package ${req.packageSpec}`);
  }

  next();
}

export default asyncHandler(validateVersion);