require 'rails_helper'

RSpec.describe Projecao::CalculoDeProjecao, type: :model do
	it{ is_expected.to have_many(:indices_do_calculo_de_projecao).dependent(:destroy) }
	it{ is_expected.to have_many(:indices_de_projecao).through(:indices_do_calculo_de_projecao) }

	it{ is_expected.to have_many(:receitas_dos_calculos_de_projecao).dependent(:restrict_with_exception) }
	it{ is_expected.to have_many(:calculo_por_exercicios).through(:receitas_dos_calculos_de_projecao) }
	it{ is_expected.to have_many(:receitas).through(:receitas_dos_calculos_de_projecao) }

	it{ is_expected.to validate_presence_of :projecao_de_receita_id }
	it{ is_expected.to validate_presence_of(:memoria_de_calculo).with_message('Memória de cálculo não pode ficar em branco') }
	it{ is_expected.to validate_presence_of(:exercicio_base).with_message('o exercicio base não pode ficar em branco') }
	it{ is_expected.to validate_presence_of(:exercicio_destino).with_message('o exercicio destino não pode ficar em branco') }

	it { is_expected.to validate_numericality_of(:exercicio_base).is_less_than(9999).with_message('o exercicio base não é um ano') }
	it { is_expected.to validate_numericality_of(:exercicio_destino).is_less_than(9999).with_message('o exercicio destino não é um ano') }

	describe '#valor_exercicio_base' do
		context "quando exercicio_base é igual ou maior que exercicio_destino" do
			it "retorna mensagem de erro" do
				calculo_de_projecao = FactoryBot.build( :calculo_de_projecao_para_2017 )
				calculo_de_projecao.exercicio_base = 2017
				calculo_de_projecao.save

				expect( calculo_de_projecao.errors[:exercicio_base] ).to include 'o exercicio base deve ser menor que o exercício destino'
			end
		end
	end

	describe '#validates_inclusion_of' do
		before do
		  @calculo = FactoryBot.build( :calculo_de_projecao_para_2017 )
		end

		context "quando seleciona o exercício base" do
			it 'retorna mensagem de erro' do
				@calculo.exercicio_base = 2012
				@calculo.save

				expect(@calculo.errors[:exercicio_base]).to include 'o exercício base selecionado para o cálculo de projeção deve estar entre o exercício inicial e final da base de cálculo da projeção de receita'
			end
		end

		context "quando seleciona o exercício destino" do
			it 'retorna mensagem de erro' do
				@calculo.exercicio_destino = 2021
				@calculo.save

				expect(@calculo.errors[:exercicio_destino]).to include 'o exercício destino selecionado para o cálculo de projeção deve estar entre o exercício inicial e final de projeção da projeção de receita'
			end
		end
	end

	describe '.receitas_projetadas' do
		it 'retorna as receitas que já foram projetadas baseadas no exercício base e destino do cálculo determinado' do
			ppa = FactoryBot.create(:ppa_fortaleza_2020)
			projecao = ppa.projecao_de_receita
			projecao.update(receitas_importadas: true)
			calculo_receita_base = FactoryBot.create(:calculo_do_exercicio_de_2016, :receita, importado: true)
			calculo_de_projecao_01 = FactoryBot.create( :calculo_de_projecao_para_2017, projecao_de_receita_id: projecao.id, exercicio_base: 2016, exercicio_destino: 2017)
			FactoryBot.create( :igpm_aplicado_para_projecao_2017, calculo_de_projecao_id: calculo_de_projecao_01.id )
			receita_projetada_01 = FactoryBot.create( :projecao_receita_do_calculo_de_projecao, calculo_de_projecao_id: calculo_de_projecao_01.id, receita_id: calculo_receita_base.receita.id )
			FactoryBot.create( :calculo_do_exercicio_de_2016, :receita_do_calculo_de_projecao, receita_do_calculo_de_projecao_id: receita_projetada_01.id )

			calculo_de_projecao_02 = calculo_de_projecao_01.dup
			calculo_de_projecao_02.exercicio_base = calculo_de_projecao_01.exercicio_destino
			calculo_de_projecao_02.exercicio_destino = calculo_de_projecao_01.exercicio_destino + 1
			calculo_de_projecao_02.save
			FactoryBot.create( :igpm_aplicado_para_projecao_2017, calculo_de_projecao_id: calculo_de_projecao_02.id )
			receita_projetada_02 = FactoryBot.create( :projecao_receita_do_calculo_de_projecao, calculo_de_projecao_id: calculo_de_projecao_02.id, receita_id: calculo_receita_base.receita.id )
			FactoryBot.create( :calculo_do_exercicio_de_2016, :receita_do_calculo_de_projecao, receita_do_calculo_de_projecao_id: receita_projetada_02.id )

			expect(Projecao::CalculoDeProjecao.receitas_projetadas(projecao, calculo_de_projecao_01.exercicio_destino, calculo_de_projecao_01.exercicio_destino + 1)).to eq([calculo_receita_base.receita.id])
		end
	end

	describe '.copiar_para_anos_seguintes' do
		it 'retorna uma cópia de um cálculo projetado com: exercício_base igual exercício_destino do calculo copiado e exercício_destino = exercício_destino + 1 do calculo copiado ' do
			ppa = FactoryBot.create(:ppa_fortaleza_2020)
			projecao = ppa.projecao_de_receita
			projecao.update(receitas_importadas: true)
			calculo_receita_base = FactoryBot.create(:calculo_do_exercicio_de_2016, :receita, importado: true)
			calculo_de_projecao_01 = FactoryBot.create( :calculo_de_projecao_para_2017, projecao_de_receita_id: projecao.id, exercicio_base: 2016, exercicio_destino: 2017 )
			indice_de_projecao = FactoryBot.create( :igpm_aplicado_para_projecao_2017, calculo_de_projecao_id: calculo_de_projecao_01.id )

			indice_de_projecao.indice_de_projecao.projecoes_do_indice.each do |projecao_indice|
				projecao_indice.update(percentual: 20)
			end

			receita_projetada_01 = FactoryBot.create( :projecao_receita_do_calculo_de_projecao, calculo_de_projecao_id: calculo_de_projecao_01.id, receita_id: calculo_receita_base.receita.id )
			FactoryBot.create( :calculo_do_exercicio_de_2016, :receita_do_calculo_de_projecao, receita_do_calculo_de_projecao_id: receita_projetada_01.id )
			receitas_projetadas_ids = Projecao::CalculoDeProjecao.receitas_projetadas( projecao, calculo_de_projecao_01.exercicio_destino, calculo_de_projecao_01.exercicio_destino + 1 )

			expect(Projecao::CalculoDeProjecao.copiar_para_anos_seguintes(calculo_de_projecao_01, receitas_projetadas_ids)).to be_a(Projecao::CalculoDeProjecao)
		end

		it 'realiza a progressão do indice de acordo com o ano' do
			indice_de_projecao = FactoryBot.create :igpm
			projecao_de_receita = indice_de_projecao.projecao_de_receita

			projecao_de_receita.exercicios_destino.each_with_index do |exercicio, index|
				indice_de_projecao.projecoes_do_indice.create(exercicio: exercicio, percentual: index+1, fonte_da_projecao: 'BACEN')
			end

			calculo_receita_base = FactoryBot.create(:calculo_do_exercicio_de_2016, :receita, importado: true)
			indices_do_calculo_de_projecao = FactoryBot.create(:igpm_aplicado_para_projecao_2017)
			calculo_de_projecao = indices_do_calculo_de_projecao.calculo_de_projecao
			FactoryBot.create( :projecao_receita_do_calculo_de_projecao, calculo_de_projecao_id: calculo_de_projecao.id, receita_id: calculo_receita_base.receita.id )
			receitas_projetadas_ids = Projecao::CalculoDeProjecao.receitas_projetadas( projecao_de_receita, calculo_de_projecao.exercicio_destino, calculo_de_projecao.exercicio_destino + 1 )
			novo_calculo = Projecao::CalculoDeProjecao.copiar_para_anos_seguintes(calculo_de_projecao, receitas_projetadas_ids)

			expect(novo_calculo.indices_do_calculo_de_projecao.count). to eq 1
			expect(novo_calculo.indices_do_calculo_de_projecao.first.percentual). to eq indice_de_projecao.projecoes_do_indice.find_by(exercicio: 2018).percentual
		end
	end

	describe "#projecao_tem_receita_importada" do
		context 'quando não possui receita importada' do
			it 'retorna erro' do
				ppa = Ppa::Ppa.find_or_create_by!( FactoryBot.attributes_for :ppa_fortaleza_2020 )
				calculo = FactoryBot.build( :calculo_de_projecao_para_2017, projecao_de_receita_id: ppa.projecao_de_receita.id )
				calculo.save
				expect(calculo.errors[:exercicio_base]).to include 'para criar calculo, a receita deve estar importada na projeção.'
			end
		end
	end
end
