class GestaoDeEstoque::ItemDaDevolucaoDeMaterial < ApplicationRecord
  has_paper_trail

  belongs_to :devolucao_de_material, class_name: "GestaoDeEstoque::DevolucaoDeMaterial"
  belongs_to :item, class_name: "Base::Item"
  belongs_to :unidade_de_medida, class_name: "UnidadeDeMedida"

  validates_presence_of :item_id, :quantidade_devolvida, :unidade_de_medida_id
  validate :quantidade_devolvida_nao_pode_ser_maior

  def adiciona_ou_atualiza_saldo_no_estoque
    if self.devolucao_de_material.origem_type == 'GestaoDeEstoque::Transferencia'
      estoque_saida = GestaoDeEstoque::Estoque.where(item_id: self.item_id, unidade_de_medida_id: self.unidade_de_medida_id,
        unidade_orcamentaria_id: self.devolucao_de_material.origem.unidade_orcamentaria_de_destino_id,
        almoxarifado_id: self.devolucao_de_material.origem.almoxarifado_de_destino_id).first

      self.adiciona_movimentacao_no_estoque(estoque_saida, 'saida')

      estoque_entrada = GestaoDeEstoque::Estoque.where(item_id: self.item_id, unidade_de_medida_id: self.unidade_de_medida_id,
        unidade_orcamentaria_id: self.devolucao_de_material.origem.unidade_orcamentaria_id,
        almoxarifado_id: self.devolucao_de_material.origem.almoxarifado_id).first

      self.adiciona_movimentacao_no_estoque(estoque_entrada, 'entrada')
    elsif self.devolucao_de_material.origem_type == 'Administrativo::RequisicaoDeMaterial'
      estoque_saida = GestaoDeEstoque::Estoque.where(item_id: self.item_id, unidade_de_medida_id: self.unidade_de_medida_id,
        unidade_orcamentaria_id: self.devolucao_de_material.origem.unidade_orcamentaria_id,
        almoxarifado_id: self.devolucao_de_material.origem.almoxarifado_destino_id).first

      self.adiciona_movimentacao_no_estoque(estoque_saida, 'saida')

      estoque_entrada = GestaoDeEstoque::Estoque.where(item_id: self.item_id, unidade_de_medida_id: self.unidade_de_medida_id,
        unidade_orcamentaria_id: self.devolucao_de_material.origem.unidade_orcamentaria_id,
        almoxarifado_id: self.devolucao_de_material.origem.almoxarifado_id).first

      self.adiciona_movimentacao_no_estoque(estoque_entrada, 'entrada')
    end
	end

	def adiciona_movimentacao_no_estoque(estoque, tipo)
		begin
      if estoque.present? && estoque.persisted?
				GestaoDeEstoque::MovimentacaoDoEstoque.create!(
					estoque_id: estoque.id,
					quantidade_saida: tipo == 'saida' ? self.quantidade_devolvida.to_f : 0,
          quantidade_entrada: tipo == 'entrada' ? self.quantidade_devolvida.to_f : 0,
					origem_id: self.devolucao_de_material.id,
					origem_type: self.devolucao_de_material.class.name,
					orcamento_id: self.devolucao_de_material.origem.orcamento_id,
					unidade_orcamentaria_id: estoque.unidade_orcamentaria_id,
					almoxarifado_id: estoque.almoxarifado_id,
          valor_unitario: estoque.calcular_valor_medio_por_data_final(self.devolucao_de_material.data_de_devolucao),
					valor_total: (self.quantidade_devolvida.to_f * estoque.calcular_valor_medio_por_data_final(self.devolucao_de_material.data_de_devolucao)).to_f
				)
        self.desconta_saldo_do_sub_estoque if tipo == 'saida'
			end
		rescue Exception => e
			raise e
		end
	end

  def desconta_saldo_do_sub_estoque
    quantidade = self.quantidade_devolvida

    while(quantidade > 0)
      sub_estoque_menor_validade = self.estoque.sub_estoques_por_validade.where("quantidade > 0 ").order("validade ASC").first rescue nil
      break if sub_estoque_menor_validade.nil?
      if quantidade >= sub_estoque_menor_validade.quantidade
        quantidade = quantidade - sub_estoque_menor_validade.quantidade
        sub_estoque_menor_validade.update_attribute(:quantidade, 0)
      else
        sub_estoque_menor_validade.update_attribute(:quantidade, sub_estoque_menor_validade.quantidade - quantidade)
        break
      end
    end
  end

  def valor_unitario_medio
    estoque = GestaoDeEstoque::Estoque.where(item_id: self.item_id, unidade_de_medida_id: self.unidade_de_medida_id, almoxarifado_id: self.devolucao_de_material.requisicao_de_material.almoxarifado_id, unidade_orcamentaria_id: self.devolucao_de_material.requisicao_de_material.unidade_orcamentaria_id).try(:first)
    estoque.calcular_valor_medio_por_data_final(self.devolucao_de_material.data_de_devolucao).to_f rescue 0
  end

  def valor_total
    quantidade_devolvida.to_f * valor_unitario_medio.to_f rescue 0
  end

  #verificar com a Brenna
  def quantidade_total_do_item
    if self.devolucao_de_material.origem_type == 'GestaoDeEstoque::Transferencia'
      quantidade_item = self.devolucao_de_material.origem.itens_da_transferencia.where(item_id: self.item_id).sum(:quantidade).to_f rescue 0
    elsif self.devolucao_de_material.origem_type == 'Administrativo::RequisicaoDeMaterial'
      quantidade_item = self.devolucao_de_material.origem.itens_das_requisicoes_de_materiais.where(item_id: self.item_id).sum(:quantidade_requisitada).to_f rescue 0
    end
    return quantidade_item
  end

  def quantidade_disponivel
    quantidade_devolvida_de_outros_total = GestaoDeEstoque::DevolucaoDeMaterial.joins(:itens_das_devolucoes_de_materiais).where(origem: self.devolucao_de_material.origem, origem_type: self.devolucao_de_material.origem_type).where.not('gestao_de_estoque_itens_das_devolucoes_de_materiais.devolucao_de_material_id = ?', self.devolucao_de_material.id).to_a.sum(&:itens_das_devolucoes_de_materiais).sum(&:quantidade_devolvida).to_f rescue 0
    if self.devolucao_de_material.origem_type == 'GestaoDeEstoque::Transferencia'
      quantidade_item = self.devolucao_de_material.origem.itens_da_transferencia.where(item_id: self.item_id).sum(:quantidade).to_f rescue 0
    elsif self.devolucao_de_material.origem_type == 'Administrativo::RequisicaoDeMaterial'
      quantidade_item = self.devolucao_de_material.origem.itens_das_requisicoes_de_materiais.where(item_id: self.item_id).sum(:quantidade_requisitada).to_f rescue 0
    end
    return (quantidade_item - quantidade_devolvida_de_outros_total - self.quantidade_devolvida.to_f)
  end

  def quantidade_devolvida_nao_pode_ser_maior
    if self.devolucao_de_material.origem_type == 'GestaoDeEstoque::Transferencia'
      quantidade_item = self.devolucao_de_material.origem.itens_da_transferencia.where(item_id: self.item_id).sum(:quantidade).to_f
    elsif self.devolucao_de_material.origem_type == 'Administrativo::RequisicaoDeMaterial'
      quantidade_item = self.devolucao_de_material.origem.itens_das_requisicoes_de_materiais.where(item_id: self.item_id).sum(:quantidade_requisitada).to_f rescue 0
    end
    quantidade_devolvida_de_outros_total = GestaoDeEstoque::DevolucaoDeMaterial.joins(:itens_das_devolucoes_de_materiais).where(origem: self.devolucao_de_material.origem, origem_type: self.devolucao_de_material.origem_type).where.not('gestao_de_estoque_itens_das_devolucoes_de_materiais.devolucao_de_material_id = ?', self.devolucao_de_material.id).to_a.sum(&:itens_das_devolucoes_de_materiais).sum(&:quantidade_devolvida).to_f rescue 0

    if (quantidade_item < self.quantidade_devolvida.to_f || (quantidade_devolvida_de_outros_total + self.quantidade_devolvida.to_f) > quantidade_item)
      errors.add(:quantidade_devolvida, "não pode ser maior que a disponível.")
    end
  end

end
