class MalwareScanner
  def self.call(**args)
    new(**args).call
  end

  LOCAL_COMMAND     = %w[clamdscan --fdpass --no-summary].freeze
  CONTAINER_COMMAND = %w[clamdscan -c config/clamd.container.conf --stream --no-summary].freeze

  def initialize(file_path:, uploader: nil, file_details: nil, save_result: true)
    @file_path    = file_path
    @uploader     = uploader
    @file_details = file_details
    @save_result  = save_result
  end

  def call
    result = MalwareScanResult.new(
      uploader: uploader,
      virus_found: virus_found?,
      scan_result: scan_result.result,
      scanner_working: scanner_working?,
      file_details: file_details
    )

    result.save! if save_result

    result
  end

  private

  attr_reader :file_path, :uploader, :file_details, :save_result

  def virus_found?
    @virus_found ||= !scan_result.status.success?
  end

  def scanner_working?
    return true unless scan_result.status.exitstatus == 2

    Sentry.capture_message("ClamdscanError, #{scan_result.error.presence || scan_result.result}")
    false
  end

  def scan_result
    @scan_result ||= begin
      stdout, stderr, status = Open3.capture3(*(command + [file_path.to_s]))
      result = stdout.strip

      OpenStruct.new(
        result: result,
        status: status,
        error: stderr
      )
    end
  end

  def command
    ENV['LOCAL_CLAMAV'] == 'true' ? LOCAL_COMMAND : CONTAINER_COMMAND
  end
end
