class GestaoDeEstoque::Estoque < ApplicationRecord
  has_paper_trail

  include TradutorConcern

	belongs_to :item, class_name: 'Base::Item'
	belongs_to :unidade_de_medida, class_name: 'UnidadeDeMedida'
  belongs_to :almoxarifado, class_name: 'GestaoDeEstoque::Almoxarifado'
  belongs_to :unidade_orcamentaria, class_name: 'Loa::UnidadeOrcamentaria'
  belongs_to :orcamento, class_name: "::Orcamento"
  belongs_to :sub_elemento_de_despesa, class_name: "Contabilidade::SubElementoDeDespesa"
  belongs_to :classificacao_do_detalhamento, class_name: "Contabilidade::SubElementoDeDespesa", foreign_key: :classificacao_do_detalhamento_id
  belongs_to :programa_por_escola, class_name: "GestaoDeEstoque::ProgramaPorEscola"

	has_many :movimentacoes_do_estoque, class_name: 'GestaoDeEstoque::MovimentacaoDoEstoque', dependent: :destroy
  has_many :sub_estoques_por_validade
  has_many :itens_do_consumo, class_name: "GestaoDeEstoque::ItemDoConsumo"

  validates_uniqueness_of :item_id, scope: [:unidade_de_medida_id, :almoxarifado_id, :unidade_orcamentaria_id, :sub_elemento_de_despesa_id, :programa_por_escola_id]

  enum tipo_de_material: {
		consumo: 0,
		permanente: 1,
		consumo_distribuicao_gratuita: 2
	}

  def descricao_item
    self.item.try(:codigo_e_descricao_do_item)
  end

	def unidade_de_medida_descricao
		self.unidade_de_medida.present? ? self.unidade_de_medida.descricao : self.item.unidade_de_medida.descricao
	end

  #Quantidades
  def quantidade_anterior_total(data_inicial)
    entradas = self.movimentacoes_do_estoque.where(
      "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_entrada > 0
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
    ).sum(:quantidade_entrada).to_f rescue 0.0

    saidas = self.movimentacoes_do_estoque.where(
      "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao < ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_saida > 0
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
    ).sum(:quantidade_saida).to_f rescue 0.0

    return (entradas.to_f - saidas.to_f)
  end

  def quant_entra(data_inicio, data_final)
    self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ?
      AND quantidade_entrada > 0', data_inicio, data_final).sum(:quantidade_entrada) rescue 0.0
  end

  def quant_saida(data_inicio, data_final)
    self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ?
      AND quantidade_saida > 0', data_inicio, data_final).sum(:quantidade_saida) rescue 0.0
  end

  def quantidade_total(data_inicio, data_final)
    quantidade_anterior_total(data_inicio) + (quant_entra(data_inicio, data_final) - quant_saida(data_inicio, data_final))
  end

  #Valores
  def valor_anterior_total(data_inicial)
    entradas = self.movimentacoes_do_estoque.where(
      "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_entrada > 0
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
    ).sum(:valor_total).to_f rescue 0.0

    saidas = self.movimentacoes_do_estoque.where(
      "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao < ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_saida > 0
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
    ).sum(:valor_total).to_f rescue 0.0

    return (entradas.to_f - saidas.to_f)
  end

  def valor_total_entradas(data_inicio = nil, data_final = nil)
    if data_inicio.present? && data_final.present?
      self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ? AND quantidade_entrada > 0', data_inicio, data_final).sum(:valor_total) rescue 0.0
    else
      self.movimentacoes_do_estoque.where('origem_type is not null AND quantidade_entrada > 0').sum(:valor_total) rescue 0.0
    end
  end

  def valor_total_saidas(data_inicio = nil, data_final = nil)
    if data_inicio.present? && data_final.present?
      self.movimentacoes_do_estoque.where('data_da_movimentacao >= ? AND data_da_movimentacao <= ? AND quantidade_saida > 0', data_inicio, data_final).sum(:valor_total) rescue 0.0
    else
      self.movimentacoes_do_estoque.where('quantidade_saida > 0').sum(:valor_total) rescue 0.0
    end
  end

  def valor_total_saldo(data_inicio = nil, data_final = nil)
    if data_inicio.present?
      valor_anterior_total(data_inicio) + (valor_total_entradas(data_inicio, data_final) - valor_total_saidas(data_inicio, data_final))
    else
      valor_total_entradas(data_inicio, data_final).to_f - valor_total_saidas(data_inicio, data_final).to_f
    end
  end

  #Quantidades

  # def quantidade_anterior_total(data_inicial)
  #   entradas = self.movimentacoes_do_estoque.where(
  #     "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_entrada > 0
  #     AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
  #   ).sum(:quantidade_entrada).to_f rescue 0.0

  #   saidas = self.movimentacoes_do_estoque.where(
  #     "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao < ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_saida > 0
  #     AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
  #   ).sum(:quantidade_saida).to_f rescue 0.0

  #   return (entradas.to_f - saidas.to_f)
  # end

  def quantidade_total_entradas_nao_disponivel
    GestaoDeEstoque::MovimentacaoDoEstoque.where(estoque_id: self.id).sum(:quantidade_entrada).to_f rescue 0.0
  end

  def quantidade_total_saidas_nao_disponivel
    GestaoDeEstoque::MovimentacaoDoEstoque.where(estoque_id: self.id).sum(:quantidade_saida).to_f rescue 0.0
  end

  def quantidade_total_entradas
		GestaoDeEstoque::MovimentacaoDoEstoque.where(orcamento: contexto_atual).where(estoque_id: self.id, unidade_orcamentaria_id: self.unidade_orcamentaria_id).sum(:quantidade_entrada).to_f rescue 0.0
	end

	def quantidade_total_saidas
		GestaoDeEstoque::MovimentacaoDoEstoque.where(orcamento: contexto_atual).where(estoque_id: self.id, unidade_orcamentaria_id: self.unidade_orcamentaria_id).sum(:quantidade_saida).to_f rescue 0.0
	end

  def quantidade_total_entradas_completos(data_inicio = nil, data_final = nil)
    if data_inicio.present? || data_final.present?
      data_inicio = Date.new(contexto_atual.exercicio, 1, 1) unless data_inicio.present?
      data_final = Date.today unless data_final.present?
      self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ? AND quantidade_entrada > 0', data_inicio, data_final).sum(:quantidade_entrada) rescue 0.0
    else
      self.movimentacoes_do_estoque.where('origem_type is not null AND quantidade_entrada > 0').sum(:quantidade_entrada).to_f rescue 0.0
    end
	end

	def quantidade_total_saidas_completos(data_inicio = nil, data_final = nil)
    if data_inicio.present? || data_final.present?
      data_inicio = Date.new(contexto_atual.exercicio, 1, 1) unless data_inicio.present?
      data_final = Date.today unless data_final.present?
      self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ? AND quantidade_saida > 0', data_inicio, data_final).sum(:quantidade_saida) rescue 0.0
    else
      self.movimentacoes_do_estoque.where('origem_type is not null AND quantidade_saida > 0').sum(:quantidade_saida).to_f rescue 0.0
    end
	end

  def periodo_sem_movimentacao
    @configuracoes = Configuracao.includes(:parametrizacao_modulos).last

    if ultima_movimentacao_de_saida.present?
      periodo = "#{ultima_movimentacao_de_saida.try(:data_da_movimentacao)} - #{Date.today}".html_safe rescue ""
    else
      periodo = "Não existe nenhuma movimentação de saída para esse estoque."
    end
    return periodo
  end

  def primeira_movimentacao
    self.movimentacoes_do_estoque.first rescue nil
  end

  def ultima_movimentacao
    self.movimentacoes_do_estoque.last rescue nil
  end

  def ultima_movimentacao_de_entrada
    self.movimentacoes_do_estoque.where('quantidade_entrada > 0').last rescue nil
  end

  def ultima_movimentacao_de_saida
    self.movimentacoes_do_estoque.where('quantidade_saida > 0').last rescue nil
  end

  def entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.tipo_de_material = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.almoxarifado_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.origem_type = 'GestaoDeEstoque::RecebimentoDeMaterial'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao >= ?
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ?
      ", GestaoDeEstoque::Estoque.tipos_de_materiais[self.tipo_de_material.to_sym], self.almoxarifado_id, self.unidade_orcamentaria_id, data_inicial.to_date, data_final.to_date
    ).sum(:quantidade_entrada).to_f rescue 0.0
  end

  def saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.tipo_de_material = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.almoxarifado_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.origem_type = 'Administrativo::RequisicaoDeMaterial'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao >= ?
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ?
      ", GestaoDeEstoque::Estoque.tipos_de_materiais[self.tipo_de_material.to_sym], self.almoxarifado_id, self.unidade_orcamentaria_id, data_inicial.to_date, data_final.to_date
    ).sum(:quantidade_saida).to_f rescue 0.0
  end

  def entradas_dos_estoques_ate_data(data = nil)
    data = Date.today if data.nil?
    GestaoDeEstoque::MovimentacaoDoEstoque.where(estoque_id: self.id, unidade_orcamentaria_id: self.unidade_orcamentaria_id).where('data_da_movimentacao <= ?', data.to_date).sum(:quantidade_entrada).to_f rescue 0.0
  end

  def saidas_dos_estoques_ate_data(data = nil)
    data = Date.today if data.nil?
    GestaoDeEstoque::MovimentacaoDoEstoque.where(estoque_id: self.id, unidade_orcamentaria_id: self.unidade_orcamentaria_id).where('data_da_movimentacao <= ?', data.to_date).sum(:quantidade_saida).to_f rescue 0.0
  end

  def quantidade_total_por_data(data = nil)
    data = Date.today if data.nil?
    entradas_dos_estoques_ate_data(data.to_date) - saidas_dos_estoques_ate_data(data.to_date)
  end

  # Essa def deve retornar a quantidade do estoque - a quantidade que já foi solicitada anteriormente no consumo especifico
  def quantidade_total_no_consumo(data = nil, consumo = nil)
    data = Date.today if data.nil?
    quantidade = GestaoDeEstoque::ItemDoConsumoPorPrograma.joins(:programa_por_consumo)
      .where('consumo_id = ? and estoque_id = ?', consumo.to_i, self.id).pluck(:quantidade).sum

    (quantidade_total_por_data(data.to_date) - quantidade)
  end

  # Essa def deve retornar a quantidade do estoque - a quantidade que já foi solicitada anteriormente na transferência especifica
  def quantidade_total_na_transferencia(data = nil, transferencia = nil)
    data = Date.today if data.nil?
    quantidade = GestaoDeEstoque::ItemDoProgramaPorAlmoxarifadoETransferencia.joins(:programa_por_almoxarifado_e_transferencia)
      .where('transferencia_id = ? and estoque_id = ?', transferencia.to_i, self.id).pluck(:quantidade).sum

    (quantidade_total_por_data(data.to_date) - quantidade)
  end

  def entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.tipo_de_material = #{GestaoDeEstoque::Estoque.tipos_de_materiais[self.tipo_de_material.to_sym]}
      AND gestao_de_estoque_estoques.sub_elemento_de_despesa_id = #{self.sub_elemento_de_despesa_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.almoxarifado_id = #{self.almoxarifado_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = #{self.unidade_orcamentaria_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.origem_type = 'GestaoDeEstoque::RecebimentoDeMaterial'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao >= '#{data_inicial.to_date}'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= '#{data_final.to_date}'"
    ).sum(:quantidade_entrada).to_f rescue 0.0
  end

  def saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.tipo_de_material = #{GestaoDeEstoque::Estoque.tipos_de_materiais[self.tipo_de_material.to_sym]}
      AND gestao_de_estoque_estoques.sub_elemento_de_despesa_id = #{self.sub_elemento_de_despesa_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.almoxarifado_id = #{self.almoxarifado_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = #{self.unidade_orcamentaria_id}
      AND gestao_de_estoque_movimentacoes_do_estoque.origem_type = 'Administrativo::RequisicaoDeMaterial'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao >= '#{data_inicial.to_date}'
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= '#{data_final.to_date}'
      "
    ).sum(:quantidade_saida).to_f rescue 0.0
  end

  def total_dos_estoques_com_mesmo_sub_elemento(data_inicial, data_final)
    entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final) - saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)
  end

  # def valor_total_entradas(data_inicio = nil, data_final = nil)
  #   if data_inicio.present? || data_final.present?
  #     data_inicio = Date.new(contexto_atual.exercicio, 1, 1) unless data_inicio.present?
  #     data_final = Date.today unless data_final.present?
  #     self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao <= ? AND quantidade_entrada > 0', data_inicio, data_final).sum(:valor_total) rescue 0.0
  #   else
  #     self.movimentacoes_do_estoque.where('origem_type is not null AND quantidade_entrada > 0').sum(:valor_total).to_f rescue 0.0
  #   end
	# end

	# def valor_total_saidas(data_inicio = nil, data_final = nil)
  #   if data_inicio.present? || data_final.present?
  #     data_inicio = Date.new(contexto_atual.exercicio, 1, 1) unless data_inicio.present?
  #     data_final = Date.today unless data_final.present?
  #     self.movimentacoes_do_estoque.where('origem_type is not null AND data_da_movimentacao >= ? AND data_da_movimentacao < ? AND quantidade_saida > 0', data_inicio, data_final).sum(:valor_total) rescue 0.0
  #   else
  #     self.movimentacoes_do_estoque.where('origem_type is not null AND quantidade_saida > 0').sum(:valor_total).to_f rescue 0.0
  #   end
	# end

  def quantidade_total_saldo_nao_disponivel
		quantidade_total_entradas_nao_disponivel.to_f - quantidade_total_saidas_nao_disponivel.to_f
	end
  
	def quantidade_total_saldo
		quantidade_total_entradas.to_f - quantidade_total_saidas.to_f
	end

  def quantidade_total_saldo_completos(data_inicio = nil, data_final = nil)
    quantidade_anterior_total(data_inicio) + (quantidade_total_entradas_completos(data_inicio, data_final).to_d - quantidade_total_saidas_completos(data_inicio, data_final).to_d)
  end

  #Valores

  # def valor_anterior_total(data_inicial)
  #   entradas = self.movimentacoes_do_estoque.where(
  #     "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao <= ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_entrada > 0
  #     AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
  #   ).sum(:valor_total).to_f rescue 0.0

  #   saidas = self.movimentacoes_do_estoque.where(
  #     "gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao < ? AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_saida > 0
  #     AND gestao_de_estoque_movimentacoes_do_estoque.unidade_orcamentaria_id = ?", data_inicial.to_date, self.unidade_orcamentaria_id
  #   ).sum(:valor_total).to_f rescue 0.0

  #   if self.item.id == 4847
  #   return (entradas.to_f - saidas.to_f)
  # end

  # def valor_total_saldo(data_inicio = nil, data_final = nil)
  #   if data_inicio.present?
  #     valor_anterior_total(data_inicio) + (valor_total_entradas(data_inicio, data_final).to_f - valor_total_saidas(data_inicio, data_final).to_f)
  #   else
  #     valor_total_entradas(data_inicio, data_final).to_f - valor_total_saidas(data_inicio, data_final).to_f
  #   end
  # end

  def calcular_valor_unitario_medio
    movimentacoes = GestaoDeEstoque::MovimentacaoDoEstoque
      .where("estoque_id = ?", self.id).all
      


    total_entrada = movimentacoes.where("quantidade_entrada > 0").inject(0) { |total_entrada, movimentacao| total_entrada += (movimentacao.quantidade_entrada * movimentacao.valor_unitario).to_d.round(2) }
    total_saida = movimentacoes.where("quantidade_saida > 0").inject(0) { |total_saida, movimentacao| total_saida += (movimentacao.quantidade_saida * movimentacao.valor_unitario).to_d.round(2) }
    qtd_entrada = movimentacoes.where("quantidade_entrada > 0").inject(0) { |total_entrada, movimentacao| total_entrada += movimentacao.quantidade_entrada }
    qtd_saida = movimentacoes.where("quantidade_saida > 0").inject(0) { |total_saida, movimentacao| total_saida += movimentacao.quantidade_saida }
    if (qtd_entrada.to_d - qtd_saida.to_d) > 0
      valor_medio = ((total_entrada.to_d - total_saida.to_d) / (qtd_entrada.to_d - qtd_saida.to_d)).to_d.round(4)
    else
      valor_medio = 0
    end

    valor_medio = 0 if valor_medio.infinite?
    max_value = 10**12 - 1
    valor_medio = 0 if valor_medio.abs >= max_value
    self.update_column(:valor_unitario_medio, valor_medio)

    # ultima_entrada = GestaoDeEstoque::MovimentacaoDoEstoque.where("estoque_id = ?", self.id).order("data_da_movimentacao DESC").first

    # if ultima_entrada.present? && ultima_entrada.data_da_movimentacao.present?
    #   self.update_column(:valor_unitario_medio, self.calcular_valor_medio_por_data_final(Date.today))
    # else
    #   self.update_column(:valor_unitario_medio, 0)
    # end
  end

  def calcular_valor_medio_por_data_final(data_final)
    movimentacoes = GestaoDeEstoque::MovimentacaoDoEstoque
      .where("data_da_movimentacao <= ? and estoque_id = ?", data_final.to_date, self.id)
      .order("data_da_movimentacao", "id")
      .pluck(:quantidade_entrada, :quantidade_saida, :valor_unitario, :data_da_movimentacao, :id)

    total_entrada = 0
    total_saida = 0
    qtd_entrada = 0
    qtd_saida = 0
    valor_medio = 0
    movimentacoes.each do |quantidade_entrada, quantidade_saida, valor_unitario, data_da_movimentacao, id|
      if quantidade_entrada.to_d > 0
        data_da_ultima_entrada = data_da_movimentacao
        existem_outras_saidas = movimentacoes.select { |i| i[3] <= data_da_ultima_entrada && i[1].to_d > 0 && i[4] != id }.size > 0 ? true : false

        if data_final == data_da_movimentacao && !existem_outras_saidas
          total_entrada += quantidade_entrada * valor_unitario.to_d
          qtd_entrada += quantidade_entrada

          valor_medio = (total_entrada.to_d / qtd_entrada.to_d).to_d.round(4)
        else
          total_entrada += quantidade_entrada * valor_unitario.to_d
          qtd_entrada += quantidade_entrada

          total_saida = movimentacoes.select { |i| i[1].to_d > 0 && i[3] <= data_da_ultima_entrada}[0..-2].map{ |i| i[2] * i[1] }.sum.to_d
          qtd_saida = movimentacoes.select { |i| i[1].to_d > 0 && i[3] <= data_da_ultima_entrada}[0..-2].map{ |i| i[1] }.sum.to_d
          
          if (qtd_entrada.to_d - qtd_saida.to_d) > 0
            valor_medio = ((total_entrada.to_d - total_saida.to_d) / (qtd_entrada.to_d - qtd_saida.to_d)).to_d.round(4) rescue 0.0
          else
            valor_medio = (total_entrada.to_d / qtd_entrada.to_d).to_d.round(4)
          end
        end

        valor_medio = 0 if valor_medio.infinite?
        max_value = 10**12 - 1
        valor_medio = 0 if valor_medio.abs >= max_value
      end
    end

    return valor_medio
  end

  def descricao_codigo_na_prefeitura_e_unidade_destacada
    "#{self.item.codigo_e_descricao} <strong>(#{unidade_de_medida.descricao})</strong>".html_safe rescue ""
  end

  def unidade_de_medida_descricao
    unidade_de_medida.descricao
  end

  def saldo_por_item_e_unidade_de_medida
    entrada_por_item_e_unidade_de_medida - saida_por_item_e_unidade_de_medida
  end

  def saida_por_item_e_unidade_de_medida
    estoques = GestaoDeEstoque::Estoque.where(item_id: self.item_id , unidade_de_medida_id: self.unidade_de_medida_id)
    estoques.inject(0) { |total_saida, estoque| total_saida += estoque.quantidade_total_saidas}
  end

  def entrada_por_item_e_unidade_de_medida
    estoques = GestaoDeEstoque::Estoque.where(item_id: self.item_id , unidade_de_medida_id: self.unidade_de_medida_id)
    estoques.inject(0) { |total_entrada, estoque| total_entrada += estoque.quantidade_total_entradas}
  end

  def saldo_por_item_e_unidade_de_medida_por_data(data_do_estoque)
    entrada_por_item_e_unidade_de_medida_por_data(data_do_estoque) - saida_por_item_e_unidade_de_medida_por_data(data_do_estoque)
  end

  def saida_por_item_e_unidade_de_medida_por_data(data_do_estoque)
    estoques = self.movimentacoes_do_estoque.where(orcamento: contexto_atual).where('data_da_movimentacao <= ?', data_do_estoque).sum('COALESCE(quantidade_saida)')
  end

  def entrada_por_item_e_unidade_de_medida_por_data(data_do_estoque)
    estoques = self.movimentacoes_do_estoque.where(orcamento: contexto_atual).where('data_da_movimentacao <= ?', data_do_estoque).sum('COALESCE(quantidade_entrada)')
  end

  def saldo_por_item_e_unidade_de_medida_e_unidade_orcamentaria
    entrada_por_item_e_unidade_de_medida_e_unidade_orcamentaria - saida_por_item_e_unidade_de_medida_e_unidade_orcamentaria
  end

  def saida_por_item_e_unidade_de_medida_e_unidade_orcamentaria
    estoques = GestaoDeEstoque::Estoque.where(item_id: self.item_id , unidade_de_medida_id: self.unidade_de_medida_id, unidade_orcamentaria_id: self.unidade_orcamentaria_id)
    estoques.inject(0) { |total_saida, estoque| total_saida += estoque.quantidade_total_saidas}
  end

  def entrada_por_item_e_unidade_de_medida_e_unidade_orcamentaria
    estoques = GestaoDeEstoque::Estoque.where(item_id: self.item_id , unidade_de_medida_id: self.unidade_de_medida_id, unidade_orcamentaria_id: self.unidade_orcamentaria_id)
    estoques.inject(0) { |total_entrada, estoque| total_entrada += estoque.quantidade_total_entradas}
  end

  def sub_elemento_de_despesa_com_descricao
    self.sub_elemento_de_despesa.codigo_e_descricao
  end

  def titulo_do_tipo_de_material
    if self.tipo_de_material.present?
      return "Bens #{self.tipo_de_material_i18n}"
    else
      return ""
    end
  end

  def sub_estoque_mais_proximo_a_vencer
    self.sub_estoques_por_validade.find_by( validade: self.sub_estoques_por_validade.minimum( :validade ) )
  end

  def sub_estoque_mais_longe_a_vencer
    self.sub_estoques_por_validade.find_by( validade: self.sub_estoques_por_validade.maximum( :validade ) )
  end

  def quantidade_mais_proxima_a_vencer
    self.sub_estoque_mais_proximo_a_vencer.quantidade rescue 0
  end

  def sub_elemento_de_despesa_com_descricao
    self.sub_elemento_de_despesa.codigo_e_descricao
  end

  def classificacao_do_detalhamento_com_descricao
    self.classificacao_do_detalhamento.try(:codigo_e_descricao)
  end

  def ultima_marca_registrada
    self.movimentacoes_do_estoque.where(origem_type: "GestaoDeEstoque::RecebimentoDeMaterial").last.origem.itens_do_recebimento_de_materiais.where("gestao_de_estoque_itens_do_recebimento_de_materiais.item_id = ?", self.item_id).first.marca
  end

  def lote_de_fabricacao_do_item
    self.movimentacoes_do_estoque.where(origem_type: "GestaoDeEstoque::RecebimentoDeMaterial").last.origem.itens_do_recebimento_de_materiais.where("gestao_de_estoque_itens_do_recebimento_de_materiais.item_id = ?", self.item_id).first.try(:informacoes_extras).first.try(:lote_de_fabricacao)
  end

end
