class GestaoDeEstoque::ItemDaTransferencia < ApplicationRecord
  has_paper_trail

  include EstoqueConcern

  attr_accessor :enviando_ao_almoxarifado_pelo_patrimonio_attribute

  belongs_to :estoque , class_name: "GestaoDeEstoque::Estoque"
	belongs_to :unidade_de_medida_de_conversao, class_name: "UnidadeDeMedida", foreign_key: :unidade_de_medida_de_conversao_id
  belongs_to :transferencia, class_name: "GestaoDeEstoque::Transferencia"
  belongs_to :item, class_name: "Base::Item"
  belongs_to :programa_por_escola, class_name: 'GestaoDeEstoque::ProgramaPorEscola'

  validate :valida_quantidade

  before_save :preenche_item_id

  has_many :movimentacoes_do_estoque, as: :origem
  has_many :itens_dos_programas_por_almoxerifado_e_trnsferencia, class_name: 'GestaoDeEstoque::ItemDoProgramaPorAlmoxarifadoETransferencia'


  def preenche_item_id
    if self.estoque.present?
      self.item_id = self.estoque.item_id
      self.quantidade_disponivel = self.estoque.quantidade_total_saldo
      self.unidade_de_medida_de_conversao_id = self.estoque.unidade_de_medida_id
      self.valor_unitario = self.estoque.calcular_valor_medio_por_data_final(self.transferencia.data_de_transferencia)
      if self.quantidade.to_i > 0
        self.total = (self.estoque.calcular_valor_medio_por_data_final(self.transferencia.data_de_transferencia) * self.quantidade.to_f).to_f
      end
    else
      return false
    end
  end

  def adiciona_ou_atualiza_saldo_no_estoque
    begin
      if self.estoque_id.present?
        self.estoque.update_columns(
          saldo_da_ordem_de_compra: saldo_do_estoque
        )
        self.adiciona_movimentacao_no_estoque
      else
        estoque = GestaoDeEstoque::Estoque.new(
          item_id: self.item_id,
          unidade_de_medida_id: self.try(:item).try(:unidade_de_medida).id,
          saldo_da_ordem_de_compra: saldo_do_estoque,
          unidade_orcamentaria_id: self.transferencia.unidade_orcamentaria_id,
          almoxarifado_id: self.transferencia.almoxarifado_id,
          tipo_de_material: self.estoque.tipo_de_material,
          sub_elemento_de_despesa_id: self.estoque.sub_elemento_de_despesa_id,
          orcamento_id: self.estoque.orcamento_id
        )
        self.estoque_id = estoque.id if estoque.save
        self.adiciona_movimentacao_no_estoque
      end
      estoque_destino = GestaoDeEstoque::Estoque.where(
        item_id: self.item_id, unidade_de_medida_id: self.try(:item).try(:unidade_de_medida).id, 
        almoxarifado_id: transferencia.almoxarifado_de_destino_id, unidade_orcamentaria_id: transferencia.unidade_orcamentaria_de_destino_id, 
        programa_por_escola_id: self.programa_por_escola_id
      ).first rescue nil

      if estoque_destino.nil?
        programa = self.transferencia.usa_programa? ? self.programa_por_escola.id : nil
        estoque = GestaoDeEstoque::Estoque.new(
          item_id: self.item_id,
          unidade_de_medida_id: self.try(:item).try(:unidade_de_medida).id,
          saldo_da_ordem_de_compra: saldo_do_estoque,
          unidade_orcamentaria_id: self.transferencia.unidade_orcamentaria_de_destino_id,
          almoxarifado_id: self.transferencia.almoxarifado_de_destino_id,
          valor_unitario_medio: self.estoque.calcular_valor_medio_por_data_final(self.transferencia.data_de_transferencia),
          tipo_de_material: self.estoque.tipo_de_material,
          sub_elemento_de_despesa_id: self.estoque.sub_elemento_de_despesa_id,
          orcamento_id: self.estoque.orcamento_id,
          programa_por_escola_id: programa
        )
        estoque.save
        self.adiciona_movimentacao_no_estoque_de_destino(estoque)
      else
        self.adiciona_movimentacao_no_estoque_de_destino(estoque_destino)
      end
    rescue Exception => e
      raise e
    end
  end

  def adiciona_movimentacao_no_estoque
    begin

      if self.estoque.present? && self.estoque.persisted?
        GestaoDeEstoque::MovimentacaoDoEstoque.create!(
          estoque_id: self.estoque.id,
          quantidade_saida: self.quantidade.to_f,
          origem_id: self.transferencia.id,
          origem_type: self.transferencia.class.name,
          orcamento_id: self.transferencia.orcamento_id,
          unidade_orcamentaria_id: transferencia.unidade_orcamentaria_id,
          almoxarifado_id: transferencia.almoxarifado_id,
          valor_unitario: self.valor_unitario,
          valor_total: self.total
        )
        # self.desconta_saldo_do_sub_estoque
        # self.atualiza_saldo_no_sub_estoque(true, self.estoque)
      end
    rescue Exception => e
      raise e
    end
  end

  def adiciona_movimentacao_no_estoque_de_destino(estoque)
    begin

      if self.estoque.present? && self.estoque.persisted?
        GestaoDeEstoque::MovimentacaoDoEstoque.create!(
          estoque_id: estoque.id,
          quantidade_entrada: self.quantidade.to_f,
          origem_id: self.transferencia.id,
          origem_type: self.transferencia.class.name,
          orcamento_id: self.transferencia.orcamento_id,
          unidade_orcamentaria_id: transferencia.unidade_orcamentaria_de_destino_id,
          almoxarifado_id: transferencia.almoxarifado_de_destino_id,
          valor_unitario: self.valor_unitario,
          valor_total: self.total
        )
        self.atualiza_saldo_no_sub_estoque(estoque)
      end
    rescue Exception => e
      raise e
    end
  end

  def saldo_do_estoque
		total = estoque.quantidade_total_saldo.to_f rescue 0.0
		(total - retorna_quantidade_ou_quantidade_de_conversao.to_f).to_f
	end

  def retorna_quantidade_ou_quantidade_de_conversao
		self.quantidade
	end

  def retorna_quantidade_devolvida
    GestaoDeEstoque::ItemDaDevolucaoDeMaterial.find_by(item_id: self.item_id).quantidade_devolvida.to_f rescue 0
  end

  def desconta_saldo_do_sub_estoque
    quantidade = self.quantidade

    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 valida_quantidade
    errors.add(:quantidade, "Quantidade maior que a do estoque") if transferencia.present? && self.saldo_do_item.to_f < 0
  end

  def unidade_de_medida_destacada
    GestaoDeEstoque::Estoque.where(almoxarifado_id: self.transferencia.almoxarifado_id, unidade_orcamentaria_id: self.transferencia.unidade_orcamentaria_id , item_id: self.item_id , unidade_de_medida_id: self.unidade_de_medida_de_conversao_id).first.descricao_codigo_na_prefeitura_e_unidade_destacada rescue ""
  end

  def saldo_do_item
    if transferencia.present?
      if self.transferencia.status == "aberto"
        self.estoque&.quantidade_total_saldo.to_d - self.quantidade
      else
        self.estoque&.quantidade_total_saldo.to_d
      end
    end
  end

end
