class MiqProvisionRequest < MiqRequest
  alias_attribute :provision_type, :request_type
  alias_attribute :src_vm_id,      :source_id

  delegate :my_zone, :to => :source

  TASK_DESCRIPTION  = N_('VM Provisioning')
  SOURCE_CLASS_NAME = 'Vm'
  ACTIVE_STATES     = %w[migrated] + base_class::ACTIVE_STATES

  validates_inclusion_of :request_state,
                         :in      => %w[pending provisioned finished] + ACTIVE_STATES,
                         :message => "should be pending, #{ACTIVE_STATES.join(", ")}, provisioned, or finished"
  validates :source, :presence => true
  validate               :must_have_user

  default_value_for :options,      :number_of_vms => 1
  default_value_for(:source_id)    { |r| r.get_option(:src_vm_id) || r.get_option(:source_id) }
  default_value_for :source_type,  "VmOrTemplate"

  include MiqProvisionMixin
  include MiqProvisionQuotaMixin

  def vm_template
    source
  end

  def vm_template=(object)
    self.source = object
  end

  def miq_provisions
    miq_request_tasks
  end

  def miq_provisions=(objects)
    self.miq_request_tasks = objects
  end

  def self.request_task_class_from(attribs)
    source_id = MiqRequestMixin.get_option(:src_vm_id, nil, attribs['options'])
    vm_or_template = source_vm_or_template!(source_id)

    via = MiqRequestMixin.get_option(:provision_type, nil, attribs['options'])
    vm_or_template.ext_management_system.class.provision_class(via)
  end

  def self.source_vm_or_template!(source_id)
    vm_or_template = VmOrTemplate.find_by(:id => source_id)
    if vm_or_template.nil?
      raise MiqException::MiqProvisionError, "Unable to find source Template/Vm with id [#{source_id}]"
    end

    if vm_or_template.ext_management_system.nil?
      raise MiqException::MiqProvisionError, "Source Template/Vm with id [#{source_id}] has no EMS, unable to provision"
    end

    vm_or_template
  end

  def self.new_request_task(attribs)
    klass = request_task_class_from(attribs)
    klass.new(attribs)
  end

  def set_description(force = false)
    prov_description = nil
    if description.nil? || force == true
      prov_description = MiqProvision.get_description(self, MiqProvision.get_next_vm_name(self, false))
    end
    # Capture self.options after running 'get_next_vm_name' method since automate may update the object
    attrs = {:options => options.merge(:delivered_on => nil)}
    attrs[:description] = prov_description unless prov_description.nil?
    update(attrs)
  end

  def post_create_request_tasks
    update_description_from_tasks
  end

  def update_description_from_tasks
    return unless requested_task_idx.length == 1

    update(:description => miq_request_tasks.reload.first.description)
  end

  def my_role(_action = nil)
    'ems_operations'
  end

  def my_queue_name
    source.ext_management_system&.queue_name_for_ems_operations
  end

  def requested_task_idx
    (1..get_option(:number_of_vms).to_i).to_a
  end

  def customize_request_task_attributes(req_task_attrs, idx)
    req_task_attrs['options'][:pass] = idx
  end

  # methods to be implemented in resolution
  #
  def self.ready?(userid)
    # must have at least one dept, env
    # if env includes prod must have at least one service_level
    prov = MiqProvision.new(:userid => userid)
    dept = prov.allowed(:department)
    env  = prov.allowed(:environment)

    return false if dept.empty? || env.empty?

    prov.options[:environment] = "prod" # Set env to prod to get service levels
    svc  = prov.allowed(:service_level) # Get service levels
    return false if env.include?("prod") && svc.empty?  # Make sure we have at least one

    true
  end

  def src_vm_id=(value)
    self.source_id   = value
    self.source_type = 'VmOrTemplate'
  end

  def target
    :vms
  end

  def vms
    miq_provisions.collect(&:vm).compact
  end

  def originating_controller
    "vm"
  end

  def template_valid?
    validate_template[:valid]
  end

  def template_valid_error_message
    validate_template[:message]
  end

  def validate_template
    return {:valid   => false,
            :message => "Unable to find VM with Id [#{source_id}]"
    } if source.nil?

    return {:valid   => false,
            :message => "VM/Template <#{source.name}> with Id <#{source.id}> is archived and cannot be used with provisioning."
    } if source.archived?

    return {:valid   => false,
            :message => "VM/Template <#{source.name}> with Id <#{source.id}> is orphaned and cannot be used with provisioning."
    } if source.orphaned?

    {:valid => true, :message => nil}
  end

  def event_name(mode)
    "vm_provision_request_#{mode}"
  end

  def my_records
    "#{SOURCE_CLASS_NAME}:#{source_id.inspect}"
  end
end
