# frozen_string_literal: true

# Security::VulnerabilityFindingsFinder
#
# Used to filter Vulnerabilities::Occurrences  by set of params for Security Dashboard
#
# Arguments:
#   pipeline_ids - IDs for the pipelines to fetch vulnerabilities for
#   params:
#     severity: Array<String>
#     confidence: Array<String>
#     project: Array<String>
#     report_type: Array<String>
#     scope: String

module Security
  class VulnerabilityFindingsFinder
    attr_accessor :params
    attr_reader :include_sha, :pipeline_ids

    def initialize(pipeline_ids, params: {}, include_sha: false)
      @pipeline_ids = pipeline_ids
      @params = params
      @include_sha = include_sha
    end

    def execute
      collection = init_collection
      collection = by_report_type(collection)
      collection = by_project(collection)
      collection = by_severity(collection)
      collection = by_confidence(collection)
      collection = by_scope(collection)
      collection
    end

    private

    def by_report_type(items)
      return items unless params[:report_type].present?

      items.by_report_types(
        Vulnerabilities::Occurrence::REPORT_TYPES.values_at(
          *params[:report_type]).compact)
    end

    def by_project(items)
      return items unless params[:project_id].present?

      items.by_projects(params[:project_id])
    end

    def by_severity(items)
      return items unless params[:severity].present?

      items.by_severities(
        Vulnerabilities::Occurrence::SEVERITY_LEVELS.values_at(
          *params[:severity]).compact)
    end

    def by_confidence(items)
      return items unless params[:confidence].present?

      items.by_confidences(
        Vulnerabilities::Occurrence::CONFIDENCE_LEVELS.values_at(
          *params[:confidence]).compact)
    end

    def by_scope(items)
      # We're using the same params as the public Vulnerabilities API because the frontend uses both
      # https://gitlab.com/gitlab-org/gitlab/issues/33468 fixes issue with param name meaning
      return items if params[:scope] == 'all'

      items.undismissed
    end

    def init_collection
      if include_sha
        ::Vulnerabilities::Occurrence.for_pipelines_with_sha(pipeline_ids)
      else
        ::Vulnerabilities::Occurrence.for_pipelines(pipeline_ids)
      end
    end
  end
end
