class Contabilidade::ItemDoEmpenho < ApplicationRecord
	has_paper_trail

	attr_default :quantidade, 0.0

	belongs_to :empenho, required: true
	belongs_to :item, class_name: 'Base::Item', required: true

	delegate :descricao_do_item, to: :item
	delegate :codigo_e_descricao, to: :item

	has_many :anulacoes, inverse_of: :item_do_empenho, class_name: 'Contabilidade::AnulacaoDoItemDoEmpenho'

	validates_presence_of :item_id, :empenho_id, :quantidade, :valor_unitario, :total
	validates_numericality_of :quantidade, :valor_unitario, :total, greater_than: 0

	validate :limite_do_total_digitado_pelo_calculo, if: Proc.new{ !self.quantidade.blank? && !self.valor_unitario.blank? && !self.total.blank?}
	validate :valida_quantidade_do_item, if: Proc.new { self.empenho.present? && self.empenho.projeto.present? && self.empenho.descrimina_itens_processo_ou_contrato.present? && !self.quantidade.blank? }
	validate :valida_valor_dos_itens_por_contrato_ou_projeto, if: Proc.new { self.empenho.present? && self.empenho.projeto.present? && self.empenho.descrimina_itens_processo_ou_contrato.present?}

	scope :validos_no_orcamento, -> { where('quantidade_positiva is true') }

	def item_do_pedido
		empenho.projeto.pedido.itens_do_pedido.find_by(item: item)
	end

	def item_do_lote
		empenho.projeto.itens_do_lote.joins(:item_do_pedido).find_by(licitacao_itens_do_pedido: {item_id: item.id}) if empenho.projeto
	end

	def item_do_contrato
		empenho.contrato.itens_do_contrato.joins(item_do_lote: :item_do_pedido).find_by(licitacao_itens_do_pedido: {item_id: item.id}) if empenho.contrato
	end

	def quantidade_anulada
		anulacoes.joins(:anulacao_do_empenho).where('contabilidade_anulacoes_do_empenho.status = 3 AND quantidade > 0 AND contabilidade_anulacoes_dos_itens_do_empenho.item_do_empenho_id = ?', self.id).sum(&:quantidade)
	end

	def quantidade_cancelada_em_rp_nao_processado
		empenhos.joins(restos_a_pagar_cancelados: :cancelamento_de_resto_a_pagar).where('contabilidade_cancelamentos_de_restos_a_pagar.tipo = 0').inject(0) { |total, rp_canc|
			total + rp_canc.empenho.itens_do_empenho.where(item_id: self.item_id).sum(:quantidade).to_d
		}
	end

	def valor_cancelado_em_rp_nao_processado
		quantidade_cancelada_em_rp_nao_processado * valor_unitario
	end

	def quantidade_liquidada
		empenho.liquidacoes.where(descrimina_itens_processo_ou_empenho: true).where('de_multiplas_notas_fiscais = ? OR (de_multiplas_notas_fiscais = ? AND liquidacao_mae_id IS NOT NULL)', false, true).joins(:itens_da_nota_fiscal).where(contabilidade_itens_da_nota_fiscal: { item_id: item_id }).sum(:quantidade)
	end

	def quantidade_estornada
		empenho.liquidacoes.where(descrimina_itens_processo_ou_empenho: true, estornada: true).where('de_multiplas_notas_fiscais = ? OR (de_multiplas_notas_fiscais = ? AND liquidacao_mae_id IS NOT NULL)', false, true).joins(:itens_da_nota_fiscal).where(contabilidade_itens_da_nota_fiscal: { item_id: item_id }).sum(:quantidade)
	end

	def quantidade_disponivel
		if empenho.possui_itens_repetidos?
			empenho.itens_do_empenho.validos_no_orcamento.where(item_id: item_id).sum(:quantidade) - quantidade_anulada 
		else
			self.quantidade - quantidade_anulada
		end
	end

	def quantidade_disponivel_a_liquidar
		quantidade_disponivel  - ( quantidade_liquidada - quantidade_estornada 	)
	end

	def quantidade_de_restos_a_pagar
		if empenho.possui_itens_repetidos?
			quantidade_disponivel = empenho.itens_do_empenho.where(item_id: item_id).validos_no_orcamento.sum(:quantidade) - quantidade_anulada
		else
			quantidade_disponivel = self.quantidade - quantidade_anulada
		end
		quantidade_disponivel - quantidade_liquidada
	end

	def porcentagem_da_quantidade_disponivel_a_liquidar
		(quantidade_disponivel_a_liquidar*100)/self.quantidade
	end

	def total_anulado
		quantidade_anulada * valor_unitario
	end

	def total_disponivel
		quantidade_disponivel * valor_unitario
	end

	def total_disponivel_a_liquidar
		quantidade_disponivel_a_liquidar * valor_unitario
	end

	def quantidade_disponivel_para_empenho
		if empenho.contrato.present?
			if empenho.aditivo_id.present? && empenho.aditivo.itens_do_aditivo.any?
				quantidade_disponivel = item_do_contrato.quantidade_do_item_do_aditivo(empenho.id)
			else
				if Configuracao.last.controla_itens_por_dotacao?
					itens_orcamento = self.empenho.contrato.itens_dos_orcamentos_da_despesa_do_contrato.select { |f| f.orcamento_da_despesa_do_contrato.orcamento_da_despesa_id == self.empenho.orcamento_da_despesa_id } 
					item_selecionado = itens_orcamento.select { |f| f.item_do_contrato_id == item_do_contrato.id }
					quantidade_disponivel = item_selecionado.sum { |item_orcamento| item_orcamento.quantidade.to_d rescue 0 } - self.item_do_contrato.quantidade_empenhada_na_dotacao(self.empenho.orcamento_da_despesa_id).to_d
					if self.persisted?
						quantidade_disponivel = quantidade_disponivel - self.quantidade_was rescue 0
					end	
				elsif Configuracao.last.controlar_empenho_por_vigencia
					quantidade_disponivel =	item_do_contrato.saldo_para_empenho_no_contrato_sem_aditivo rescue 0
				else
					data_do_empenho = empenho.data_do_empenho.present? ? empenho.data_do_empenho : empenho.data_de_solicitacao
					quantidade_disponivel = item_do_contrato.saldo_para_empenho_atual(data_do_empenho) rescue 0
				end
			end
		elsif empenho.projeto.present?
			quantidade_disponivel = item_do_lote.saldo
		end
		return quantidade_disponivel
	end

	def saldo_disponivel_para_ordem_de_compra
		itens_nas_ordens_de_compra = self.empenho.ordens_de_compra.valido.joins(:itens_da_ordem_de_compra).where('licitacao_itens_da_ordem_de_compra.item_id = ?', self.item.id).sum(:quantidade).to_f
		saldo_disponivel = self.empenho.itens_do_empenho.find_by(item: self.item).quantidade_disponivel.to_f - itens_nas_ordens_de_compra
		if saldo_disponivel >= 0
			return saldo_disponivel
		else
			return 0
		end
	end

	private
	def limite_do_total_digitado_pelo_calculo
		total_calculado = self.quantidade.to_f * self.valor_unitario.to_d
		errors.add(:total, "não pode ser mais que 10 centavos do valor calculado da quantidade x preço unitário") if self.total.to_d > (total_calculado + 0.1)
		errors.add(:total, "não pode ser menos que 10 centavos do valor calculado da quantidade x preço unitário") if self.total.to_d < (total_calculado - 0.1)
	end

	def valida_quantidade_do_item
		if empenho.aditivo.present?
			origem_empenho = "aditivo"
		elsif empenho.contrato.present?
			origem_empenho = Configuracao.last.controla_itens_por_dotacao? ? "dotacao" : "contrato"
		else
			origem_empenho = "projeto"
		end
		if self.persisted?
			errors.add(:quantidade, "não pode ser maior que a quantidade do item no #{origem_empenho}") if (quantidade.to_f > quantidade_disponivel_para_empenho.to_d + self.quantidade_was)
		else
			errors.add(:quantidade, "não pode ser maior que a quantidade do item no #{origem_empenho}") if (quantidade.to_f > quantidade_disponivel_para_empenho.to_d)
		end
	end

	def valida_valor_dos_itens_por_contrato_ou_projeto
		if empenho.projeto.present?
			if empenho.contrato.present?
				errors.add(:valor_unitario, 'A soma dos valores deve ser menor ou igual ao valor do contrato escolhido') if (self.empenho.valor_a_empenhar_do_contrato_vigente.to_d + self.empenho.valor_total_do_empenho.to_d).round(2) < (self.empenho.itens_do_empenho.sum(:total).to_d + self.total.to_d - total_was.to_d).round(2)
			else
				errors.add(:valor_unitario, 'A soma dos valores deve ser menor ou igual ao valor do projeto escolhido') if self.empenho.projeto.valor_a_contratar.to_f.round(2) < (self.empenho.itens_do_empenho.sum(:total) + self.total.to_d - total_was.to_d).round(2)
			end
		end
	end
end
