require 'rails_helper'

RSpec.describe Contabilidade::AnulacaoDoEmpenho, type: :model do
	cria_configuracao_default

	#it_behaves_like "reverte eventos contábeis", "Anular", Contabilidade::AnulacaoDoEmpenho, :empenho_22090001, :anulacao_do_empenho_total
	# it_behaves_like "vistoriavel concern", "Liquidar", Contabilidade::AnulacaoDoEmpenho, :anulacao_do_empenho_total

	it{ is_expected.to belong_to( :empenho ).required }
	it{ is_expected.to belong_to( :orcamento ) }

	it { is_expected.to delegate_method(:possui_itens?).to(:empenho) }

	it{ is_expected.to have_many( :itens_anulados ).class_name("Contabilidade::AnulacaoDoItemDoEmpenho") }

	[:data_da_anulacao, :historico, :valor, :tipo_de_anulacao].each do |atributo|
		it{ is_expected.to validate_presence_of atributo }
	end

	it{ is_expected.to validate_numericality_of( :valor ).is_greater_than(0) }

	it { is_expected.to allow_value('01/01/2016').for(:data_da_anulacao) }
	it { is_expected.to_not allow_value('').for(:data_da_anulacao) }
	it { is_expected.to_not allow_value('00/').for(:data_da_anulacao) }

	it "atualiza saldo do empenho" do
		empenho = Contabilidade::Empenho.create( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao, valor: 9.99) )
		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create( FactoryBot.attributes_for(:anulacao_do_empenho_total, valor: 9.99, empenho: empenho) )
		expect(anulacao_do_empenho.empenho.saldo).to eq 0
	end

	it "atualiza saldo do empenho ao apagar" do
		empenho = Contabilidade::Empenho.create( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao, valor: 9.99, descriminacao_obrigatoria_de_itens: false) )
		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create( FactoryBot.attributes_for(:anulacao_do_empenho_total, valor: 9.99, empenho: empenho) )
		anulacao_do_empenho.destroy
		expect(empenho.reload.saldo).to eq 9.99
	end

	it "atualiza tipo de anulacao parcial" do
		empenho = Contabilidade::Empenho.find_or_create_by!( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao) )
		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create(empenho: empenho, valor: 2.00, historico: "...", data_da_anulacao: Date.today, tipo_de_anulacao: :parcial)
		expect(anulacao_do_empenho.tipo_de_anulacao).to eq "parcial"
	end

	it "atualiza tipo de anulacao total" do
		empenho = Contabilidade::Empenho.find_or_create_by!( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao, valor: 9.99) )
		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create(empenho: empenho, valor: 9.99, historico: "...", data_da_anulacao: Date.today, tipo_de_anulacao: :total)
		expect(anulacao_do_empenho.tipo_de_anulacao).to eq "total"
	end

	it "valor maior que saldo" do
		empenho = Contabilidade::Empenho.find_or_create_by!( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao, valor: 9.99) )
		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create(empenho: empenho, valor: 10.00, historico: "...", data_da_anulacao: Date.today, tipo_de_anulacao: :parcial)
		expect(anulacao_do_empenho.errors[:valor]).to include("não pode ser maior que o saldo do empenho")
	end

	context "data nao pode ser anterior a data do empenho" do
		it "data anterior a data do empenho" do
			empenho = Contabilidade::Empenho.find_or_create_by!( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao) )
			anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create(empenho: empenho, valor: 10.00, historico: "...", data_da_anulacao: empenho.data_de_solicitacao - 1.day, tipo_de_anulacao: :parcial)
			anulacao_do_empenho.validate

			expect(anulacao_do_empenho.errors[:data_da_anulacao]).to include("não pode ser anterior a data do empenho (#{empenho.data_do_empenho})")
		end

		it "data apos a data do empenho" do
			empenho = Contabilidade::Empenho.find_or_create_by!( FactoryBot.attributes_for(:empenho_22090001, :derivado_de_licitacao) )
			anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.create(empenho: empenho, valor: 10.00, historico: "...", data_da_anulacao: empenho.data_do_empenho + 1.day, tipo_de_anulacao: :parcial)
			anulacao_do_empenho.validate

			expect(anulacao_do_empenho.errors[:data_da_anulacao]).not_to include("não pode ser anterior a data do empenho (#{empenho.data_do_empenho})")
		end
	end

	describe 'valida saldo do orcamento da despesa' do
		it "quando lanca movimento orcamentario" do
			orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude))

			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_despesa, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save

			anulacao_do_empenho = FactoryBot.build(:anulacao_do_empenho_total, empenho: empenho, valor: empenho.valor)
			anulacao_do_empenho.save(validate: false)

			expect( orcamento_da_despesa.reload.valor_empenhado.to_f ).to eq 0
		end

		it "quando apaga movimento orcamentario" do
			orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude))


			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_despesa, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save

			anulacao_do_empenho = FactoryBot.build(:anulacao_do_empenho_total, empenho: empenho, valor: empenho.valor)
			anulacao_do_empenho.save(validate: false)

			anulacao_do_empenho.destroy

			expect( orcamento_da_despesa.reload.valor_empenhado.to_f ).to eq empenho.valor.to_f
		end
	end

	# context "saldo_da_dotacao_apos_a_anulacao" do
	# 	it "anulado parte do empenho" do
	# 		orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude, valor: 1000))
	#
	# 		empenho = Contabilidade::Empenho.new(valor: 600, orcamento_da_despesa: orcamento_da_despesa, data_do_empenho: Date.today, status: :confirmado, descriminacao_obrigatoria_de_itens: false)
	# 		empenho.save(validate: false)
	# 		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.new(valor: 300, data_da_anulacao: Date.today, empenho: empenho)
	# 		anulacao_do_empenho.save(validate: false)
	#
	# 		orcamento_da_despesa.atualiza_saldo_dos_lancamentos
	#
	# 		expect(anulacao_do_empenho.send(:saldo_da_dotacao_apos_a_anulacao)).to eq 700.to_f
	# 	end
	#
	# 	it "anulado totalmente" do
	# 		orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude, valor: 1000))
	#
	# 		empenho = Contabilidade::Empenho.new(valor: 600, orcamento_da_despesa: orcamento_da_despesa, data_do_empenho: Date.today, status: :confirmado, descriminacao_obrigatoria_de_itens: false)
	# 		empenho.save(validate: false)
	# 		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.new(valor: 600, data_da_anulacao: Date.today, empenho: empenho)
	# 		anulacao_do_empenho.save(validate: false)
	#
	# 		orcamento_da_despesa.atualiza_saldo_dos_lancamentos
	#
	# 		expect(anulacao_do_empenho.send(:saldo_da_dotacao_apos_a_anulacao)).to eq 1000.to_f
	# 	end
	# end

	# context "saldo_da_dotacao_antes_a_anulacao" do
	# 	it "apenas um lancamento" do
	# 		orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude, valor: 1000))
	#
	# 		empenho = Contabilidade::Empenho.new(valor: 600, orcamento_da_despesa: orcamento_da_despesa, data_do_empenho: Date.today, status: :confirmado, descriminacao_obrigatoria_de_itens: false)
	# 		empenho.save(validate: false)
	# 		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.new(valor: 600, data_da_anulacao: Date.today, empenho: empenho)
	# 		anulacao_do_empenho.save(validate: false)
	#
	# 		orcamento_da_despesa.atualiza_saldo_dos_lancamentos
	#
	# 		expect(anulacao_do_empenho.send(:saldo_da_dotacao_antes_a_anulacao)).to eq 400.to_f
	# 	end
	#
	# 	it "com dois lancamentos" do
	# 		orcamento_da_despesa = Loa::OrcamentoDaDespesa.find_or_create_by!(FactoryBot.attributes_for(:orcamento_da_despesa_saude, valor: 1000))
	#
	# 		empenho = Contabilidade::Empenho.new(valor: 400, orcamento_da_despesa: orcamento_da_despesa, data_do_empenho: Date.today, status: :confirmado, descriminacao_obrigatoria_de_itens: false)
	# 		empenho.save(validate: false)
	# 		empenho2 = Contabilidade::Empenho.new(valor: 300, orcamento_da_despesa: orcamento_da_despesa, data_do_empenho: Date.today, status: :confirmado, descriminacao_obrigatoria_de_itens: false)
	# 		empenho2.save(validate: false)
	# 		anulacao_do_empenho = Contabilidade::AnulacaoDoEmpenho.new(valor: 600, data_da_anulacao: Date.today, empenho: empenho)
	# 		anulacao_do_empenho.save(validate: false)
	#
	# 		orcamento_da_despesa.atualiza_saldo_dos_lancamentos
	#
	# 		expect(anulacao_do_empenho.send(:saldo_da_dotacao_antes_a_anulacao)).to eq 300.to_f
	# 	end
	# end

	describe '#valor_da_anulacao_igual_ao_valor_dos_itens' do
		context 'quando empenho não possui itens' do
			let(:empenho) { FactoryBot.create :empenho, :derivado_de_licitacao }
			it 'não retorna erro' do
				empenho.validate
				expect(empenho.errors[:valor]).not_to include 'deve ser igual à soma dos itens anulados'
			end
		end

		xcontext 'quando empenho possui itens' do
			before do
				item = FactoryBot.create :item_do_empenho_caderno
				outro_item = FactoryBot.create :item_do_empenho_caderno
				@empenho = item.empenho
			end
			context 'e soma dos itens anulados é igual valor anulado' do
				it 'não retorna erro' do
					anulacao_do_empenho = @empenho.anulacoes_do_empenho.new(valor: 500)
					anulacao_do_empenho.save(validate: false)
					expect(anulacao_do_empenho.errors[:valor]).not_to include 'deve ser igual à soma dos itens anulados'
				end
			end

			context 'e soma dos itens anulados é diferente valor anulado' do
				it 'retorna erro' do
					anulacao_do_empenho = empenho.anulacoes_do_empenho.new(valor: 1)
					anulacao_do_empenho.save(validate: false)
					expect(anulacao_do_empenho.errors[:valor]).to include 'deve ser igual à soma dos itens anulados'
				end
			end
		end
	end

	describe '#popula_itens_anulados' do
		let(:empenho) { FactoryBot.create :empenho, :derivado_de_licitacao }
		context 'quando anulação é parcial' do
			it 'não cria itens anulados' do
				anulacao = empenho.anulacoes_do_empenho.new(tipo_de_anulacao: :parcial)
				expect(anulacao.itens_anulados.valido.size).to be_zero
			end
		end
		context 'quando anulação é total' do
			context 'e empenho possui itens' do
				it 'cria itens anulados' do
					item = FactoryBot.create :item_do_empenho_caderno, empenho: empenho
					empenho.reload
					anulacao = empenho.anulacoes_do_empenho.new(tipo_de_anulacao: :total)
					expect(anulacao.itens_anulados.valido.size).not_to be_zero
				end
			end
			context 'e empenho não possui itens' do
				it 'não cria itens anulados' do
					anulacao = empenho.anulacoes_do_empenho.new(tipo_de_anulacao: :total)
					expect(anulacao.itens_anulados.valido.size).to be_zero
				end
			end
		end
	end

	context "Válida se número da anulação já existe no orçamento atual" do
		it "Quando não existe números iguais" do
			primeira_anulacao = FactoryBot.build(:anulacao_do_empenho_total, data_da_anulacao: "22/10/2016")
			primeira_anulacao.save(validate: false)
			segunda_anulacao = FactoryBot.build(:anulacao_do_empenho_total, data_da_anulacao: "21/10/2016")
			segunda_anulacao.validate
			expect(segunda_anulacao.errors[:numero]).to be_empty
		end
		it "Quando existe números iguais" do
			empenho = Contabilidade::Empenho.create( FactoryBot.attributes_for(:empenho_22090001, valor: 9.99, status: :confirmado, descriminacao_obrigatoria_de_itens: false) )
			primeira_anulacao = FactoryBot.build(:anulacao_do_empenho_total, empenho: empenho, data_da_anulacao: "21/10/2016", numero:"21100001", orcamento_id: 1, valor: 0.01)
			primeira_anulacao.save(validate: false)
			segunda_anulacao = FactoryBot.build(:anulacao_do_empenho_total, empenho: empenho, data_da_anulacao: "21/10/2016", numero:"21100001", orcamento_id: primeira_anulacao.orcamento_id, valor: 0.01)
			segunda_anulacao.validate
			expect(segunda_anulacao.errors[:numero]).to include "Número Já existe nesse exercicio"
		end
	end
end
