class Patrimonio::RecebimentoDeBem < ApplicationRecord
  has_paper_trail

  include AASM
  include TradutorConcern
	include IncrementadorDeCodigoConcern

  enum status: { a_receber: 1, recebido: 2, tombamento_gerado: 3, enviado_ao_almoxarifado: 4 }
	enum classificacao: { doacao: 1, confeccao: 2 , compra: 3, carta_de_setença: 4, cessao: 5, comodato: 6, implantacao: 7, locacao: 8,
    permuta: 9, reintegracao: 10, desapropriacao: 11, nascimento: 12, usucapiao: 13, dacao_em_pagamento: 14, construcao: 15, de_relancamento: 16 }

  attr_default :status, :a_receber
  attr_default :extraorcamentario, false
  attr_default :criado_no_patrimonio, false

	belongs_to :orcamento, class_name: "Orcamento"
  belongs_to :unidade_orcamentaria, class_name: "Loa::UnidadeOrcamentaria"
  belongs_to :doador, class_name: 'Base::Pessoa', foreign_key: 'doador_id'
  belongs_to :fornecedor, class_name: 'Base::Pessoa', foreign_key: 'fornecedor_id'
  belongs_to :recebimento_de_material, class_name: 'GestaoDeEstoque::RecebimentoDeMaterial'
  belongs_to :sub_elemento_de_despesa, class_name: 'Contabilidade::SubElementoDeDespesa'
  belongs_to :origem_de_recurso_patrimonial, class_name: 'Patrimonio::OrigemDeRecursoPatrimonial'
  has_many :itens_dos_recebimentos_de_bens, class_name: 'Patrimonio::ItemDoRecebimentoDeBem', dependent: :destroy
  has_many :itens, through: :itens_dos_recebimentos_de_bens
  has_many :bens_patrimoniais, through: :itens_dos_recebimentos_de_bens
  has_many :dados_extras_dos_bens, through: :itens_dos_recebimentos_de_bens
	has_many :movimentacoes_do_estoque, class_name: 'GestaoDeEstoque::MovimentacaoDoEstoque', as: :origem, dependent: :destroy
	has_many :empenhos_do_recebimento, class_name: 'Patrimonio::EmpenhoDoRecebimento', dependent: :destroy
  has_many :empenhos, through: :empenhos_do_recebimento

  accepts_nested_attributes_for :itens_dos_recebimentos_de_bens, allow_destroy: true
  accepts_nested_attributes_for :empenhos_do_recebimento, allow_destroy: true

  validates_presence_of :data_do_recebimento, :status, :classificacao, :sub_elemento_de_despesa_id, :orcamento_id, :unidade_orcamentaria_id
  validates_presence_of :ano_empenho_vinculado, if: Proc.new { self.multiplos_empenhos.present? }
  validates_presence_of :fornecedor_id, if: Proc.new { self.compra? }
  
  validate :valor_total_igual_a_soma_dos_empenhos, if: Proc.new { self.multiplos_empenhos.present? }
  validate :valida_obrigatoriedade_empenhos_do_recebimento, if: Proc.new { self.multiplos_empenhos.present? }

	before_validation :atribui_codigo_disponivel
  after_destroy :retorna_recebimento_para_recebido, if: Proc.new{ self.recebimento_de_material.present? && self.a_receber? }

  ransacker :valor_total_itens do
    query = '(SELECT SUM(valor_total) FROM patrimonio_itens_dos_recebimentos_de_bens WHERE patrimonio_itens_dos_recebimentos_de_bens.recebimento_de_bem_id = patrimonio_recebimentos_de_bens.id)'
    Arel.sql(query)
  end

  scope :recebidos_e_superiores, -> { where.not(status: :a_receber) }

  aasm column: :status, enum: true, whiny_transitions: false do
		state :a_receber, :initial => true
		state :recebido
    state :tombamento_gerado
    state :enviado_ao_almoxarifado

    event :confirmar_recebimento do
			transitions from: :a_receber, to: :recebido do
        guard do
          self.data_do_recebimento.present?
        end
        after do          
          self.itens_dos_recebimentos_de_bens.each do |item_do_recebimento_de_bem|
            item_do_recebimento_de_bem.atualiza_saldo_no_estoque
          end
        end
      end
    end

		event :gerar_bens_patrimoniais do
      transitions from: :recebido, to: :tombamento_gerado
		end

    event :reabrir do
			transitions from: :recebido, to: :a_receber do
				guard do
					self.recebido?
				end
				after do
					self.remove_movimentacao_do_estoque
				end
			end

      transitions from: :tombamento_gerado, to: :recebido do
				guard do
					self.tombamento_gerado?
				end
				after do
					self.remove_tombamentos
				end
			end
		end
	end

  def pode_voltar_etapa?
    self.recebido? || self.tombamento_gerado?
  end

  def valor_total_do_recebimento_de_bem
    self.itens_dos_recebimentos_de_bens.sum(:valor_total) rescue 0.0
  end

  def tipo_de_label
    if self.tombamento_gerado? || self.recebido?
      'success'
    else
      'info'
    end
  end

  def atribui_codigo_disponivel
		if self.data_do_recebimento.present? && self.codigo.blank?
			gerar_codigo(self.data_do_recebimento, :codigo, :data_do_recebimento, :orcamento_id, self.orcamento_id)
		end
	end

  def gera_os_bens_patrimoniais
    if self.may_gerar_bens_patrimoniais?
      ultima_sequencia = Patrimonio::BemPatrimonial.where(orcamento_id: self.orcamento.try(:id)).order(sequencia: :desc).first.try(:sequencia)
      self.itens_dos_recebimentos_de_bens.each do |item_do_recebimento_de_bem|
        ultima_sequencia = item_do_recebimento_de_bem.dados_extras_do_bem.gerar_bens_patrimoniais(ultima_sequencia)
      end
    end
  end

  def cria_transferencia
    almoxarifado_patrimonio = GestaoDeEstoque::Almoxarifado.where(orcamento_id: self.orcamento_id, tipo_de_almoxarifado: 'patrimonio').first

    transferencia = GestaoDeEstoque::Transferencia.new(
			data_de_transferencia: self.data_do_recebimento,
			almoxarifado_id: almoxarifado_patrimonio.id,
			unidade_orcamentaria_id: self.unidade_orcamentaria_id,
			almoxarifado_de_destino_id: self.recebimento_de_material.almoxarifado_id,
			unidade_orcamentaria_de_destino_id: self.recebimento_de_material.unidade_orcamentaria_id,
			orcamento_id: self.orcamento_id ,
			status: 3,
			tipo_de_material: self.recebimento_de_material.tipo_de_material,
			classificacao_tipo_de_material: self.recebimento_de_material.classificacao_tipo_de_material,
			transferir_todos_os_itens: false
		)
    if transferencia.save!
			self.itens_dos_recebimentos_de_bens.each do |item_do_recebimento|
				estoque = GestaoDeEstoque::Estoque.find_by(item_id: item_do_recebimento.item_id, unidade_de_medida_id: item_do_recebimento.unidade_de_medida_id, almoxarifado_id: almoxarifado_patrimonio.id, unidade_orcamentaria_id: self.unidade_orcamentaria_id)
				item_da_transferencia = GestaoDeEstoque::ItemDaTransferencia.create!(
					transferencia_id: transferencia.id ,
					item_id: estoque.item.id,
					quantidade: item_do_recebimento.quantidade,
					valor_unitario: estoque.calcular_valor_medio_por_data_final(self.data_do_recebimento),
					total: (item_do_recebimento.quantidade * estoque.calcular_valor_medio_por_data_final(self.data_do_recebimento)),
					estoque_id: estoque.id,
					quantidade_disponivel: estoque.quantidade_total_saldo
				)
				item_da_transferencia.adiciona_ou_atualiza_saldo_no_estoque
			end
		else
			return false
		end
  end

  def valor_total_igual_a_soma_dos_empenhos
    errors.add(:base, "O valor total do recebimento deve ser igual a soma dos empenhos.") unless self.itens_dos_recebimentos_de_bens.map{|item| item.valor_total }.sum == self.empenhos_do_recebimento.sum(:valor)
  end

  def valida_obrigatoriedade_empenhos_do_recebimento
    errors.add(:base, "É obrigatório informar pelo menos um Empenho.") if self.empenhos_do_recebimento.empty?
  end

  #Essa função fará com que o recebimento volte para a etapa de enviar para o patrimônio
  def retorna_recebimento_para_recebido
    self.recebimento_de_material.tipo_de_recebimento == "recebido" ? self.recebimento_de_material.status = "recebido" : self.recebimento_de_material.status = "recebido_parcialmente"
    self.recebimento_de_material.save(validate: false)
	end

  def remove_movimentacao_do_estoque
    GestaoDeEstoque::MovimentacaoDoEstoque.where(origem_id: self.id, origem_type: self.class.name).each do |movimentacao|
      movimentacao.destroy
    end
	end

  def remove_tombamentos
    Patrimonio::DadosExtrasDoBem.where(item_do_recebimento_de_bem: self.itens_dos_recebimentos_de_bens.ids).each do |dado|
      dado.destroy
    end
  end

  def de_veiculo?
    ['48', '50', '52', '53'].include?(sub_elemento_de_despesa.codigo)
  end
end
