# frozen_string_literal: true

require 'semver_dialects/version'
require 'semver_dialects/semantic_version/version_translator'
require 'semver_dialects/semantic_version/version_parser'
require 'semver_dialects/semantic_version/version_range'
require 'deb_version'

module SemverDialects
  # Captures all errors that could be possibly raised
  class Error < StandardError
    def initialize(msg)
      super(msg)
    end
  end

  # A utiltity module that helps with version matching
  module VersionChecker
    def self.version_translate(typ, version_string)
      case typ
      when 'maven'
        VersionTranslator.translate_maven(version_string)
      when 'npm'
        VersionTranslator.translate_npm(version_string)
      when 'conan'
        VersionTranslator.translate_conan(version_string)
      when 'nuget'
        VersionTranslator.translate_nuget(version_string)
      when 'go'
        VersionTranslator.translate_go(version_string)
      when 'gem'
        VersionTranslator.translate_gem(version_string)
      when 'pypi'
        VersionTranslator.translate_pypi(version_string)
      when 'packagist'
        VersionTranslator.translate_packagist(version_string)
      else
        raise SemverDialects::Error, "unsupported package type '#{typ}'"
      end
    end

    def self.version_sat?(typ, raw_ver, raw_constraint)
      # os package versions are handled very differently from application package versions
      return os_pkg_version_sat?(typ, raw_ver, raw_constraint) if os_purl_type?(typ)

      version_constraint = version_translate(typ, raw_constraint)
      raise SemverDialects::Error, 'malformed constraint' if version_constraint.nil? || version_constraint.empty?

      version = VersionParser.parse('=' + raw_ver)
      raise SemverDialects::Error, 'malformed constraint' if version.nil? || version.empty?

      constraint = VersionRange.new
      version_constraint.each do |version_interval_str|
        constraint << VersionParser.parse(version_interval_str)
      end

      constraint.overlaps_with?(version)
    end

    def self.os_purl_type?(typ)
      ['deb', 'rpm', 'apk'].include?(typ)
    end

    def self.os_pkg_version_sat?(typ, raw_ver, raw_constraint)
      if typ == 'deb'
        # we only support the less than operator, because that's the only one currently output
        # by the advisory exporter for operating system packages.
        raise SemverDialects::Error, 'malformed constraint' unless raw_constraint[0] == '<'

        v1 = DebVersion.new(raw_ver)
        v2 = DebVersion.new(raw_constraint[1..-1])

        return v1 < v2
      end
    end
  end
end
