class GestaoDeEstoque::MovimentacaoDoEstoque < ApplicationRecord
  has_paper_trail


  belongs_to :orcamento, class_name: 'Orcamento'
  belongs_to :estoque, class_name: 'GestaoDeEstoque::Estoque'
  belongs_to :unidade_orcamentaria, class_name: 'Loa::UnidadeOrcamentaria'
  belongs_to :almoxarifado, class_name: 'GestaoDeEstoque::Almoxarifado'
  belongs_to :origem, polymorphic: true, required: false

  after_save :atualiza_valor_unitario_medio_do_estoque, if: Proc.new { self.quantidade_entrada.present? && self.quantidade_entrada > 0 }
  before_create :salva_data_da_origem, if: Proc.new {self.origem_type.present?}
  before_create :preenche_valor_unitario_e_valor_total

  scope :empenho, -> (numero) {where(origem_type: 'GestaoDeEstoque::RecebimentoDeMaterial')
    .joins('LEFT JOIN gestao_de_estoque_recebimento_de_materiais recebimento ON recebimento.id = origem_id')
    .joins('INNER JOIN licitacao_ordens_de_compra ordem ON ordem.id = recebimento.ordem_de_compra_id ')
    .joins('INNER JOIN contabilidade_empenhos emp ON emp.id = ordem.empenho_id')
    .where('emp.numero_do_empenho = ?', numero)
  }

  scope :fornecedor, -> (fornecedor_id) {where(origem_type: 'GestaoDeEstoque::RecebimentoDeMaterial')
    .joins('LEFT JOIN gestao_de_estoque_recebimento_de_materiais recebimento ON recebimento.id = origem_id')
    .joins('INNER JOIN licitacao_ordens_de_compra ordem ON ordem.id = recebimento.ordem_de_compra_id ')
    .joins('INNER JOIN contabilidade_empenhos emp ON emp.id = ordem.empenho_id')
    .joins('INNER JOIN base_pessoas pessoa ON pessoa.id = emp.pessoa_id')
    .where('pessoa.id = ?', fornecedor_id)
  }

  scope :nota_fiscal, -> (numero_nf) {where(origem_type: 'GestaoDeEstoque::RecebimentoDeMaterial',)
    .joins('LEFT JOIN gestao_de_estoque_recebimento_de_materiais recebimento ON recebimento.id = origem_id')
    .where('recebimento.numero_da_nota = ?', numero_nf)
  }

  scope :status_entrada, -> (status) {
    status = GestaoDeEstoque::RecebimentoDeMaterial.status_de_reconhecimentos[status]
    where(origem_type: 'GestaoDeEstoque::RecebimentoDeMaterial')
    .joins('LEFT JOIN gestao_de_estoque_recebimento_de_materiais recebimento ON recebimento.id = origem_id')
    .where('recebimento.status_de_reconhecimento = ?', status)
  }

  scope :status_saida, -> (status) {
    status = GestaoDeEstoque::ItemDoConsumo.status_de_reconhecimentos[status]
    where(origem_type: 'GestaoDeEstoque::Consumo')
    .joins('LEFT JOIN gestao_de_estoque_consumos consumo ON consumo.id = origem_id')
    .joins('INNER JOIN gestao_de_estoque_itens_do_consumo item ON item.consumo_id = consumo.id')
    .where('item.status_de_reconhecimento = ?', status)
  }

  def self.ransackable_scopes(auth_object = nil)
    [:empenho, :fornecedor, :nota_fiscal, :status_entrada, :status_saida]
  end

  def total_entrada
    (valor_unitario * self.quantidade_entrada).to_f if self.quantidade_entrada.present?
  end

  def total_saida
    (valor_unitario * self.quantidade_saida).to_f if self.quantidade_saida.present?
  end

  def valor_total_entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.sub_elemento_de_despesa_id = ? 
      AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_entrada > 0
      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}'", self.estoque.sub_elemento_de_despesa_id
    ).sum(:valor_total).to_f rescue 0.0
  end

  def valor_total_saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.sub_elemento_de_despesa_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.quantidade_saida > 0
      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}'", self.estoque.sub_elemento_de_despesa_id
    ).sum(:valor_total).to_f rescue 0.0
  end

  def valor_anterior_dos_estoques_com_mesmo_sub_elemento_com_data(data)
    GestaoDeEstoque::MovimentacaoDoEstoque.joins(:estoque).where(
      "gestao_de_estoque_estoques.sub_elemento_de_despesa_id = ?
      AND gestao_de_estoque_movimentacoes_do_estoque.data_da_movimentacao >= '#{data.to_date}'", self.estoque.sub_elemento_de_despesa_id
    ).sum(:valor_total).to_f rescue 0.0
  end

  def valor_atual_dos_estoques_com_mesmo_sub_elemento(data_inicial, data_final)
    (valor_total_entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final) - valor_total_saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(data_inicial, data_final)).to_f
  end

  def retorna_tipo
    self.quantidade_entrada.to_i > 0 ? "Entrada" : "Saída"
  end

  def atualiza_valor_unitario_medio_do_estoque
    self.estoque.calcular_valor_medio_por_data_final(self.data_da_movimentacao)
  end

  def retorna_ug_e_almoxarifado
    "#{unidade_orcamentaria.codigo_e_nome} - #{almoxarifado.codigo_e_nome}"
  end

  def salva_data_da_origem
    if self.origem_type == "Administrativo::RequisicaoDeMaterial"
      self.data_da_movimentacao = self.origem.data_da_requisicao.nil? ? self.origem.data_do_recebimento : self.origem.data_da_requisicao
    elsif self.origem_type == "GestaoDeEstoque::Consumo"
      self.data_da_movimentacao = self.origem.data_de_consumo
    elsif self.origem_type == "GestaoDeEstoque::Transferencia"
      self.data_da_movimentacao = self.origem.data_de_transferencia
    elsif self.origem_type == "GestaoDeEstoque::DevolucaoDeMaterial"
      self.data_da_movimentacao = self.origem.data_da_devolucao
    elsif self.origem_type == "GestaoDeEstoque::RecebimentoDeMaterial"
      self.data_da_movimentacao = self.origem.data_do_recebimento
    elsif self.origem_type == "Patrimonio::RecebimentoDeBem"
      self.data_da_movimentacao = self.origem.data_do_recebimento
    end
  end

	def preenche_valor_unitario_e_valor_total
    if self.origem_type == "GestaoDeEstoque::Consumo"
      self.valor_unitario = self.estoque.calcular_valor_medio_por_data_final(self.data_da_movimentacao)
    end
    if self.valor_total.to_f == 0
      if quantidade_saida.to_f > 0
        self.valor_total = ( (self.try(:valor_unitario) rescue 0) * (self.try(:quantidade_saida) rescue 0) rescue 0 ).round(2)
      elsif quantidade_entrada > 0
        self.valor_total = ( (self.try(:valor_unitario) rescue 0) * (self.try(:quantidade_entrada) rescue 0) rescue 0 ).round(2)
      end
    end
	end

end
