# frozen_string_literal: true

require 'bundler/setup'
require 'semver_dialects'
require 'benchmark/ips'

# Constraints that span multiple intervals so overlaps_with? actually iterates,
# hitting both the Semver2 and SemanticVersion comparison paths.
SATISFIES_CASES = [
  ['npm',       '1.5.0', '>=1.0.0 <2.0.0 || >=3.0.0 <4.0.0'],
  ['npm',       '9.9.9', '>=1.0.0 <2.0.0 || >=3.0.0 <4.0.0'],
  ['pypi',      '1.2.3', '>=1.0.0,<2.0.0'],
  ['packagist', '1.2.3', '>=1.0.0 <2.0.0'],
  ['maven',     '1.2.3', '[1.0.0,2.0.0)'],
  ['conan',     '1.2.3', '>=1.0.0 <2.0.0']
].freeze

# A range repeated many times yields many logically-equal intervals. Interval
# defines == but not hash/eql?, so the Set that used to back IntervalSet stored
# every one of these as a distinct object (object identity) and never
# deduplicated. overlaps_with? scans linearly regardless, so the Set only ever
# added hashing cost on add. This case makes that overhead visible.
DUP_CONSTRAINT = (['>=1.0.0 <2.0.0'] * 100).join(' || ')
DUP_INTERVAL_SET = SemverDialects::IntervalSetParser.parse('npm', DUP_CONSTRAINT)
# Worst case: a version that matches nothing forces a scan of every interval.
NON_MATCH = SemverDialects::Interval.from_version(SemverDialects.parse_version('npm', '99.0.0'))

# Direct comparison microbenchmarks for the SemanticVersion path.
SV_PRERELEASE_A = SemverDialects::SemanticVersion.new('1.2.3-alpha.1.beta')
SV_PRERELEASE_B = SemverDialects::SemanticVersion.new('1.2.3-alpha.2')
SV_EQUAL_A = SemverDialects::SemanticVersion.new('1.2.3')
SV_EQUAL_B = SemverDialects::SemanticVersion.new('1.2.3')

Benchmark.ips do |x|
  x.config(time: 4, warmup: 2)

  x.report('version_satisfies?-mixed') do
    SATISFIES_CASES.each do |(typ, ver, con)|
      SemverDialects.version_satisfies?(typ, ver, con)
    end
  end

  x.report('SemanticVersion#<=> prerelease') { SV_PRERELEASE_A <=> SV_PRERELEASE_B }
  x.report('SemanticVersion#<=> equal') { SV_EQUAL_A <=> SV_EQUAL_B }

  # Building the set: the old Set paid a hash per add for no dedup benefit.
  x.report('IntervalSet build (100 dup intervals)') do
    SemverDialects::IntervalSetParser.parse('npm', DUP_CONSTRAINT)
  end

  # Scanning the set: linear over the intervals either way.
  x.report('IntervalSet#overlaps_with? (100 dup intervals)') do
    DUP_INTERVAL_SET.overlaps_with?(NON_MATCH)
  end
end
