module ForemanOpenscap::HostExtensions

def self.prepended(base)

def self.prepended(base)
  base.has_one :asset, :as => :assetable, :class_name => "::ForemanOpenscap::Asset", :dependent => :destroy
  base.has_many :asset_policies, :through => :asset, :class_name => "::ForemanOpenscap::AssetPolicy"
  base.has_many :policies, :through => :asset_policies, :class_name => "::ForemanOpenscap::Policy"
  base.has_many :arf_reports, :class_name => '::ForemanOpenscap::ArfReport', :foreign_key => :host_id
  base.has_one :compliance_status_object, :class_name => '::ForemanOpenscap::ComplianceStatus', :foreign_key => 'host_id'
  base.validate :openscap_proxy_in_taxonomy, :if => Proc.new { |host| host.openscap_proxy_id.present? }
  base.scoped_search :relation => :policies, :on => :name, :complete_value => true, :rename => :compliance_policy,
                :only_explicit => true, :operators => ['= '], :ext_method => :search_by_policy_name
  base.scoped_search :relation => :policies, :on => :id, :complete_value => false, :rename => :compliance_policy_id,
                :only_explicit => true, :operators => ['= ', '!= '], :ext_method => :search_by_policy_id
  base.scoped_search :relation => :policies, :on => :name, :complete_value => true, :rename => :compliance_report_missing_for,
                :only_explicit => true, :operators => ['= ', '!= '], :ext_method => :search_by_missing_arf
  base.scoped_search :relation => :compliance_status_object, :on => :status, :rename => :compliance_status,
                :complete_value => { :compliant => ::ForemanOpenscap::ComplianceStatus::COMPLIANT,
                                     :incompliant => ::ForemanOpenscap::ComplianceStatus::INCOMPLIANT,
                                     :inconclusive => ::ForemanOpenscap::ComplianceStatus::INCONCLUSIVE }
  base.scoped_search :relation => :policies, :on => :name, :complete_value => { :true => true, :false => false },
                     :only_explicit => true, :rename => :is_compliance_host, :operators => ['= '], :ext_method => :search_for_any_with_policy,
                     :validator => ->(value) { ['true', 'false'].include? value }
  base.scoped_search :on => :id, :rename => :passes_xccdf_rule,
          :only_explicit => true, :operators => ['= '], :ext_method => :search_by_rule_passed
  base.scoped_search :on => :id, :rename => :fails_xccdf_rule,
          :only_explicit => true, :operators => ['= '], :ext_method => :search_by_rule_failed
  base.scoped_search :on => :id, :rename => :others_xccdf_rule,
          :only_explicit => true, :operators => ['= '], :ext_method => :search_by_rule_othered
  base.scoped_search :on => :id, :rename => :comply_with,
                     :only_explicit => true, :operators => ['= '], :ext_method => :search_by_comply_with
  base.scoped_search :on => :id, :rename => :not_comply_with,
                     :only_explicit => true, :operators => ['= '], :ext_method => :search_by_not_comply_with
  base.scoped_search :on => :id, :rename => :inconclusive_with,
                     :only_explicit => true, :operators => ['= '], :ext_method => :search_by_inconclusive_with
  base.scoped_search :on => :id, :rename => :removed_from_policy,
                     :only_explicit => true, :operators => ['= '], :ext_method => :search_by_removed_from_policy
  base.scope :comply_with, lambda { |policy|
    joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).merge(ArfReport.passed)
  }
  base.scope :not_comply_with, lambda { |policy|
    joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).merge(ArfReport.failed)
  }
  base.scope :inconclusive_with, lambda { |policy|
    joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).merge(ArfReport.othered)
  }
  base.scope :policy_reports_missing, lambda { |policy|
    search_for("compliance_report_missing_for = \"#{policy.name}\"")
  }
  base.scope :assigned_to_policy, lambda { |policy|
    search_for("compliance_policy = \"#{policy.name}\"")
  }
  base.scope :removed_from_policy, lambda { |policy|
    joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).where.not(:id => assigned_to_policy(policy).pluck(:id))
  }
  base.send :extend, ClassMethods
  base.apipie :class do
    property :policies_enc, String, desc: 'Returns JSON string containing policies for the host'
    property :policies_enc_raw, array_of: Hash, desc: 'Returns a list with key:value objects containing policies for the host'
  end
  base.smart_proxy_reference :self => [:openscap_proxy_id]
end

def combined_policies

def combined_policies
  inc = %i[scap_content scap_content_profile tailoring_file tailoring_file_profile]
  combined = self.hostgroup ? self.policies.includes(inc) + self.hostgroup.policies.includes(inc) + self.hostgroup.inherited_policies : self.policies.includes(inc)
  combined.uniq
end

def compliance_status(options = {})

def compliance_status(options = {})
  @compliance_status ||= get_status(ForemanOpenscap::ComplianceStatus).to_status(options)
end

def compliance_status_label(options = {})

def compliance_status_label(options = {})
  @compliance_status_label ||= get_status(ForemanOpenscap::ComplianceStatus).to_label(options)
end

def get_asset

def get_asset
  ForemanOpenscap::Asset.where(:assetable_type => 'Host::Base', :assetable_id => id).first_or_create!
end

def inherited_attributes

def inherited_attributes
  super.concat(%w[openscap_proxy_id])
end

def last_report_for_policy(policy)

def last_report_for_policy(policy)
  reports_for_policy(policy, 1)
end

def openscap_proxy_in_taxonomy

def openscap_proxy_in_taxonomy
  validate_association_taxonomy(:openscap_proxy)
end

def policies=(policies)

def policies=(policies)
  self.build_asset(:assetable => self) if self.asset.blank?
  self.asset.policies = policies
end

def policies_enc

def policies_enc
  policies_enc_raw.to_json
end

def policies_enc_raw

def policies_enc_raw
  combined_policies.map(&:to_enc)
end

def reports_for_policy(policy, limit = nil)

def reports_for_policy(policy, limit = nil)
  report_scope = ForemanOpenscap::ArfReport.unscoped.joins(:policy_arf_report)
                                           .merge(ForemanOpenscap::PolicyArfReport.of_policy(policy.id)).where(:host_id => id)
                                           .order("#{ForemanOpenscap::ArfReport.table_name}.created_at DESC")
  report_scope = report_scope.limit(limit) if limit
  report_scope
end

def scap_status_changed?(policy)

def scap_status_changed?(policy)
  last_reports = reports_for_policy(policy, 2)
  return false if last_reports.length != 2
  !last_reports.first.equal? last_reports.last
end