# frozen_string_literal: true

module Facter
  module Resolvers
    module Windows
      class Virtualization < BaseResolver
        init_resolver

        class << self
          # Virtual
          # Is_Virtual

          MODEL_HASH = {
            'VirtualBox' => 'virtualbox',
            'VMware' => 'vmware',
            'KVM' => 'kvm',
            'Bochs' => 'bochs',
            'Google' => 'gce',
            'OpenStack' => 'openstack',
            'AHV' => 'ahv'
          }.freeze

          private

          def post_resolve(fact_name, _options)
            @fact_list.fetch(fact_name) { read_fact_from_computer_system(fact_name) }
          end

          def read_fact_from_computer_system(fact_name)
            win = Facter::Util::Windows::Win32Ole.new
            comp = win.exec_query('SELECT Manufacturer,Model,OEMStringArray FROM Win32_ComputerSystem')
            unless comp
              @log.debug 'WMI query returned no results for Win32_ComputerSystem with values'\
              ' Manufacturer, Model and OEMStringArray.'
              return
            end

            build_fact_list(comp)
            @fact_list[fact_name]
          end

          def determine_hypervisor_by_model(comp)
            MODEL_HASH[MODEL_HASH.keys.find { |key| comp.Model =~ /^#{key}/ }]
          end

          def determine_hypervisor_by_manufacturer(comp)
            manufacturer = comp.Manufacturer
            if comp.Model =~ /^Virtual Machine/ && manufacturer =~ /^Microsoft/
              'hyperv'
            elsif /^Xen/.match?(manufacturer)
              'xen'
            elsif /^(Amazon EC2|QEMU)/.match?(manufacturer)
              'kvm'
            else
              'physical'
            end
          end

          def build_fact_list(comp)
            @fact_list[:oem_strings] = []
            @fact_list[:oem_strings] += comp.to_enum.map(&:OEMStringArray).flatten

            comp = comp.to_enum.first
            hypervisor = determine_hypervisor_by_model(comp) || determine_hypervisor_by_manufacturer(comp)

            @fact_list[:virtual] = hypervisor
            @fact_list[:is_virtual] = hypervisor.include?('physical') ? false : true
          end
        end
      end
    end
  end
end
