# frozen_string_literal: true

require_relative '../../utils.rb'

# A prepropcessor -- convert different version strings to something that can be digested by the
# version parser
module VersionTranslator
  def self.translate_npm(version_string)
    version_string.split('||').map do |item|
      add_missing_operator(single_space_after_operator(item.strip.gsub(/&&/, ' ')))
    end
  end

  def self.translate_conan(version_string)
    translate_npm(version_string)
  end

  def self.translate_go(version_string)
    translate_gem(version_string)
  end

  def self.translate_gem(version_string)
    version_string.split('||').map do |item|
      add_missing_operator(single_space_after_operator(item.strip.gsub(/\s+/, ' ')))
    end
  end

  def self.translate_packagist(version_string)
    translate_pypi(version_string)
  end

  def self.translate_pypi(version_string)
    version_string.split('||').map do |item|
      add_missing_operator(single_space_after_operator(comma_to_space(item)))
    end
  end

  def self.translate_nuget(version_string)
    translate_maven(version_string)
  end

  def self.translate_maven(version_string)
    lexing_maven_version_string(version_string).map { |item| translate_mvn_version_item(item) }
  end

  def self.add_missing_operator(version_string)
    starts_with_operator?(version_string) ? version_string : "=#{version_string}"
  end

  def self.single_space_after_operator(version_string)
    version_string.gsub(/([>=<]+) +/, '\1').gsub(/\s+/, ' ')
  end

  def self.starts_with_operator?(version_item)
    version_item.match(/^[=><]/) ? true : false
  end

  def self.comma_to_space(version_string)
    version_string.strip.gsub(/,/, ' ')
  end

  def self.lexing_maven_version_string(version_string)
    open = false
    substring = ''
    ret = []
    version_string.each_char do |c|
      case c
      when '(', '['
        if open
          puts "malformed maven version string #{version_string}"
          exit(-1)
        else
          unless substring.empty?
            ret << substring
            substring = ''
          end
          open = true
          substring += c
        end
      when ')', ']'
        if !open
          puts "malformed maven version string #{version_string}"
          exit(-1)
        else
          open = false
          substring += c
          ret << substring
          substring = ''
        end
      when ','
        substring += c if open
      when ' '
        # nothing to do
        substring += ''
      else
        substring += c
      end
    end
    if open
      puts "malformed maven version string #{version_string}"
      exit(-1)
    end
    ret << substring unless substring.empty?
    ret
  end

  def self.parenthesized?(version_item)
    version_item.match(/^[\(\[]/) && version_item.match(/[\]\)]$/) ? true : false
  end

  def self.translate_mvn_version_item(version_item)
    content = ''
    parens_pattern = ''
    if parenthesized?(version_item)
      content = version_item[1, version_item.size - 2]
      parens_pattern = version_item[0] + version_item[version_item.size - 1]
      # special case -- unversal version range
      return '=*' if content.strip == ','
    else
      # according to the doc, if there is a plain version string in maven, it means 'starting from version x'
      # https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8903
      content = "#{version_item},"
      parens_pattern = '[)'
    end

    args = content.split(',')
    first_non_empty_arg = args.find(&:range_present?)

    if content.start_with?(',')
      # {,y}
      case parens_pattern
      when '[]'
        "<=#{first_non_empty_arg}"
      when '()'
        "<#{first_non_empty_arg}"
      when '[)'
        "<#{first_non_empty_arg}"
      else
        # par_pattern == "(]"
        "<=#{first_non_empty_arg}"
      end
    elsif content.end_with?(',')
      # {x,}
      case parens_pattern
      when '[]'
        ">=#{first_non_empty_arg}"
      when '()'
        ">#{first_non_empty_arg}"
      when '[)'
        ">=#{first_non_empty_arg}"
      else
        # par_pattern == "(]"
        ">#{first_non_empty_arg}"
      end
    elsif content[','].nil?
      # [x,x]
      "=#{content}"
    else
      case parens_pattern
      when '[]'
        ">=#{args[0]} <=#{args[1]}"
      when '()'
        ">#{args[0]} <#{args[1]}"
      when '[)'
        ">=#{args[0]} <#{args[1]}"
      else
        # par_pattern == "(]"
        ">#{args[0]} <=#{args[1]}"
      end
    end
  end
end
