// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
import { INVALID, MAX } from "./constants.ts";
import { satisfies } from "./satisfies.ts";
import type { Comparator, Range, SemVer } from "./types.ts";
import { greaterThan } from "./greater_than.ts";
import { isWildcardComparator } from "./_shared.ts";

function comparatorMax(comparator: Comparator): SemVer {
  const semver = comparator;
  if (isWildcardComparator(comparator)) return MAX;
  switch (comparator.operator) {
    case "!=":
    case ">":
    case ">=":
      return MAX;
    case undefined:
    case "=":
    case "<=":
      return {
        major: semver.major,
        minor: semver.minor,
        patch: semver.patch,
        prerelease: semver.prerelease,
        build: semver.build,
      };
    case "<": {
      const patch = semver.patch - 1;
      const minor = patch >= 0 ? semver.minor : semver.minor - 1;
      const major = minor >= 0 ? semver.major : semver.major - 1;
      // if you try to do <0.0.0 it will Give you -∞.∞.∞
      // which means no SemVer can compare successfully to it.
      if (major < 0) return INVALID;

      return {
        major,
        minor: minor >= 0 ? minor : Number.POSITIVE_INFINITY,
        patch: patch >= 0 ? patch : Number.POSITIVE_INFINITY,
        prerelease: [],
        build: [],
      };
    }
  }
}

/**
 * The maximum valid SemVer for a given range or INVALID
 *
 * @example Usage
 * ```ts
 * import { parseRange } from "@std/semver/parse-range";
 * import { rangeMax } from "@std/semver/range-max";
 * import { equals } from "@std/semver/equals";
 * import { assert } from "@std/assert/assert";
 *
 * assert(equals(rangeMax(parseRange(">1.0.0 <=2.0.0")), { major: 2, minor: 0, patch: 0 }));
 * ```
 *
 * @param range The range to calculate the max for
 * @returns A valid SemVer or INVALID
 *
 * @deprecated This will be removed in 1.0.0. Use {@linkcode greaterThanRange} or
 * {@linkcode lessThanRange} for comparing ranges and SemVers. The maximum
 * version of a range is often not well defined, and therefore this API
 * shouldn't be used. See
 * {@link https://github.com/denoland/deno_std/issues/4365} for details.
 */
export function rangeMax(range: Range): SemVer {
  let max;
  for (const comparators of range) {
    for (const comparator of comparators) {
      const candidate = comparatorMax(comparator);
      if (!satisfies(candidate, range)) continue;
      max = (max && greaterThan(max, candidate)) ? max : candidate;
    }
  }
  return max ?? INVALID;
}

// denoCacheMetadata={"headers":{"alt-svc":"h3=\":443\"; ma=86400","content-type":"text/typescript","access-control-expose-headers":"*","cross-origin-resource-policy":"cross-origin","cf-ray":"a223e657ca787db6-LAX","accept-ranges":"bytes","etag":"\"b5a61b560b354d0b1ce9ae92fdaf2697\"","x-content-type-options":"nosniff","content-length":"2572","x-jsr-backend":"modules","x-robots-tag":"noindex","content-security-policy":"default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; frame-src 'none'; object-src 'none'; frame-ancestors 'none'; sandbox; form-action 'none';","vary":"Origin","age":"830909","set-cookie":"__cf_bm=8rcUmB0xnfrW.gdyVLWOSmpdK5nwEUP9RbfHF2o605k-1785241875.1650848-1.0.1.1-pYurJT8oYZrWF4zaqe3vLqBEUGa_rrjAixDJoFrnpJc9hRo6EGLbZNV7QGykyCNxldIfOSH.ZeEMDHjV1Xspbs2.cnVgY_AXVqqBPk_DB2gx8Ug1Vitw.k35QIZnGqyA; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","date":"Tue, 28 Jul 2026 12:31:15 GMT","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","cache-control":"public, max-age=31536000, immutable","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=CpDDxgHKoYUCq97TnkOGBuMqpN0JiCvPlPDmHymAy18NR7ogJThJ23XaqLROsUKW%2Bf1ADedprIC7JF8NeBwYf5zcT%2F7C61GYWDsgayqE3UyPTRntj8D0VSA%3D\"}]}","access-control-allow-origin":"*","server":"cloudflare","cf-cache-status":"HIT"},"url":"https://jsr.io/@std/semver/0.224.3/range_max.ts","time":1785241875}