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

function comparatorIntersects(
  c0: Comparator,
  c1: Comparator,
): boolean {
  const op0 = c0.operator;
  const op1 = c1.operator;

  if (op0 === undefined) {
    // if c0 is empty comparator, then returns true
    if (isWildcardComparator(c0)) return true;
    return satisfies(c0, [[c1]]);
  }
  if (op1 === undefined) {
    if (isWildcardComparator(c1)) return true;
    return satisfies(c1, [[c0]]);
  }

  const cmp = compare(c0, c1);

  const sameDirectionIncreasing = (op0 === ">=" || op0 === ">") &&
    (op1 === ">=" || op1 === ">");
  const sameDirectionDecreasing = (op0 === "<=" || op0 === "<") &&
    (op1 === "<=" || op1 === "<");
  const sameSemVer = cmp === 0;
  const differentDirectionsInclusive = (op0 === ">=" || op0 === "<=") &&
    (op1 === ">=" || op1 === "<=");
  const oppositeDirectionsLessThan = cmp === -1 &&
    (op0 === ">=" || op0 === ">") &&
    (op1 === "<=" || op1 === "<");
  const oppositeDirectionsGreaterThan = cmp === 1 &&
    (op0 === "<=" || op0 === "<") &&
    (op1 === ">=" || op1 === ">");

  return sameDirectionIncreasing ||
    sameDirectionDecreasing ||
    (sameSemVer && differentDirectionsInclusive) ||
    oppositeDirectionsLessThan ||
    oppositeDirectionsGreaterThan;
}

function rangesSatisfiable(ranges: Range[]): boolean {
  return ranges.every((r) => {
    // For each OR at least one AND must be satisfiable
    return r.some((comparators) => comparatorsSatisfiable(comparators));
  });
}

function comparatorsSatisfiable(comparators: Comparator[]): boolean {
  // Comparators are satisfiable if they all intersect with each other
  for (let i = 0; i < comparators.length - 1; i++) {
    const c0 = comparators[i]!;
    for (const c1 of comparators.slice(i + 1)) {
      if (!comparatorIntersects(c0, c1)) {
        return false;
      }
    }
  }
  return true;
}

/**
 * The ranges intersect every range of AND comparators intersects with a least one range of OR ranges.
 *
 * @example Usage
 * ```ts
 * import { parseRange, rangeIntersects } from "@std/semver";
 * import { assert, assertFalse } from "@std/assert";
 *
 * const r0 = parseRange(">=1.0.0 <2.0.0");
 * const r1 = parseRange(">=1.0.0 <1.2.3");
 * const r2 = parseRange(">=1.2.3 <2.0.0");
 *
 * assert(rangeIntersects(r0, r1));
 * assert(rangeIntersects(r0, r2));
 * assertFalse(rangeIntersects(r1, r2));
 * ```
 *
 * @param r0 range 0
 * @param r1 range 1
 * @returns returns true if the given ranges intersect, false otherwise
 */
export function rangeIntersects(
  r0: Range,
  r1: Range,
): boolean {
  return rangesSatisfiable([r0, r1]) &&
    r0.some((r00) => {
      return r1.some((r11) => {
        return r00.every((c0) => {
          return r11.every((c1) => comparatorIntersects(c0, c1));
        });
      });
    });
}

// denoCacheMetadata={"headers":{"x-robots-tag":"noindex","etag":"\"41b94097674d8e419115febc33f11f5b\"","cf-cache-status":"HIT","content-length":"3065","vary":"Origin","access-control-allow-origin":"*","server":"cloudflare","cross-origin-resource-policy":"cross-origin","set-cookie":"__cf_bm=euLogeknmW5tSNt.v8G0B3WcsFTMz7baK7lyfkKHedw-1785241875.164996-1.0.1.1-AtLcoh.fh8FznLD.uxsCgRxOaS1Z9xTi4exE4WBjnwMmfdkDbS4oyaXkCDZ8gHgxZJSIUdUcO_YJ1_oJaVgwwUYEjbOTxamcjSnu1OffA_wSvx.h.OGnVJvc9IT4TvU.; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","age":"1644062","access-control-expose-headers":"*","x-jsr-backend":"modules","alt-svc":"h3=\":443\"; ma=86400","accept-ranges":"bytes","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=0A6IW59ciKM42PvinJSQcwSNaL7NhBpXiRGi8hdxe%2BGCOiEWSPWBJZpDEtV5GPaRTVTX8UImhNgzeobM8W7gKFKExp5RLQ7w9X2am7WhvqPWH0SBBq0WwLo%3D\"}]}","date":"Tue, 28 Jul 2026 12:31:15 GMT","cache-control":"public, max-age=31536000, immutable","cf-ray":"a223e657ca767db6-LAX","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';","x-content-type-options":"nosniff","content-type":"text/typescript","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}"},"url":"https://jsr.io/@std/semver/0.224.3/range_intersects.ts","time":1785241875}