# typed: strict
# frozen_string_literal: true

class Version
  class Parser
    extend T::Helpers

    abstract!

    sig { abstract.params(spec: Pathname).returns(T.nilable(String)) }
    def parse(spec); end
  end

  class RegexParser < Parser
    extend T::Helpers

    abstract!

    sig { params(regex: Regexp, block: T.nilable(T.proc.params(arg0: String).returns(String))).void }
    def initialize(regex, &block)
      super()
      @regex = regex
      @block = block
    end

    sig { override.params(spec: Pathname).returns(T.nilable(String)) }
    def parse(spec)
      match = @regex.match(self.class.process_spec(spec))
      return if match.blank?

      version = match.captures.first
      return if version.blank?
      return @block.call(version) if @block.present?

      version
    end

    sig { params(spec: Pathname).returns(String) }
    def self.process_spec(spec)
      raise NotImplementedError, "#{name}.process_spec must be implemented for #{spec}"
    end
  end

  class UrlParser < RegexParser
    sig { override.params(spec: Pathname).returns(String) }
    def self.process_spec(spec)
      spec.to_s
    end
  end

  class StemParser < RegexParser
    SOURCEFORGE_DOWNLOAD_REGEX = %r{(?:sourceforge\.net|sf\.net)/.*/download$}
    NO_FILE_EXTENSION_REGEX = /\.[^a-zA-Z]+$/

    sig { override.params(spec: Pathname).returns(String) }
    def self.process_spec(spec)
      spec_s = spec.to_s
      return spec.dirname.stem if spec_s.match?(SOURCEFORGE_DOWNLOAD_REGEX)
      return spec.basename.to_s if spec_s.match?(NO_FILE_EXTENSION_REGEX)

      spec.stem
    end
  end
end
