module Debci
  class RejectList
    def initialize
      @config_dir = Debci.config.config_dir
      @suite_list = Debci.config.suite_list
      @arch_list = Debci.config.arch_list
    end

    def unpack_params(params)
      suite = params[:suite] || '*'
      arch = params[:arch] || '*'
      version = params[:version] || '*'
      [suite, arch, version]
    end

    def include?(name, params = {})
      name = String(name)
      suite, arch, version = unpack_params(params)

      return find_expanding_package_name(name, params) unless data.key?(name)
      return find_expanding_wildcards(name, params) unless data[name].key?(suite)
      return find_expanding_wildcards(name, params) unless data[name][suite].key?(arch)

      return true if [version, '*'].include?(data[name][suite][arch].keys.first)

      find_expanding_wildcards(name, params)
    end

    def find_expanding_package_name(name, params)
      suite, arch, version = unpack_params(params)
      # Expand package name
      data.keys.select { |k| File.fnmatch(k, name) }.each do |wildcard|
        return true if include?(wildcard, suite: suite, arch: arch, version: version)
      end
      # None of the package name wildcards match
      false
    end

    def find_expanding_wildcards(name, params)
      suite, arch, version = unpack_params(params)

      if suite == '*'
        return @suite_list.all? do |s|
          include?(name, suite: s, arch: arch, version: version)
        end
      end

      return unless arch == '*'

      @arch_list.all? do |a|
        include?(name, suite: suite, arch: a, version: version)
      end
    end

    def comment(name, params = {})
      suite, arch, version = unpack_params(params)
      data.dig(name, suite, arch, version)
    end

    def packages
      # A package is rejectlisted only if it is rejectlisted for all suites,
      # architectures and versions.
      @packages ||= data.keys.select { |key| !key.include?("*") && include?(key) }
    end

    def data
      @data ||= read_data
    end

    private

    def read_data
      reject_list_file = File.join(@config_dir, 'reject_list')
      blacklist_file = File.join(@config_dir, 'blacklist')
      unless File.exist?(reject_list_file)
        return {} unless File.exist?(blacklist_file)

        Debci.warn("#{blacklist_file} is deprecated; please rename it to #{reject_list_file}")
        reject_list_file = blacklist_file
      end
      data = {}
      reason = ''
      File.readlines(reject_list_file).each do |line|
        case line
        when /^\s*$/
          true # skip blank lines
        when /^\s*#/
          old_str = %r{(https?://\S*)}
          new_str = '<a href="\1">\1</a>'
          reason << line.sub(/^\s*#\s*/, '').gsub(old_str, new_str)
        else
          pkg, suite, arch, version = line.strip.split

          suite ||= '*'
          arch ||= '*'
          version ||= '*'

          data[pkg] ||= {}
          suites = if suite == '*'
                     @suite_list
                   else
                     [suite]
                   end
          suites.each do |s|
            data[pkg][s] ||= {}
            arches = if arch == '*'
                       @arch_list
                     else
                       [arch]
                     end
            arches.each do |a|
              data[pkg][s][a] ||= {}
              data[pkg][s][a][version] = reason
            end
          end

          reason = ''
        end
      end
      data
    end
  end
end