require 'rails_helper'

RSpec.describe Ppa::Convenio, type: :model do
	cria_tipos_de_despesa

	let(:convenio_com_receita) {
		receita_corrente = FactoryBot.create(:receita_corrente)
		receita_de_capital = FactoryBot.create(:receita_de_capital)

		convenio = FactoryBot.create(:ppa_convenio, receita_corrente_id: receita_corrente.id, receita_de_capital_id: receita_de_capital.id)
		convenio
	}

	let(:convenio_com_valores) {
		convenio_receita = convenio_com_receita

		atributos =  {
			"valores_do_convenio_attributes" => {
				"0" => {
					"id" => convenio_receita.valores_do_convenio[0].id,
					"valor" => "100"
				},
				"1" => {
					"id" => convenio_receita.valores_do_convenio[1].id,
					"valor" => "300"
				},
				"2" => {
					"id" => convenio_receita.valores_do_convenio[2].id,
					"valor" => "0"
				},
				"3" => {
					"id" => convenio_receita.valores_do_convenio[3].id,
					"valor" => "0"
				},
				"4" => {
					"id" => convenio_receita.valores_do_convenio[4].id,
					"valor" => "0"
				},
				"5" => {
					"id" => convenio_receita.valores_do_convenio[5].id,
					"valor" => "0"
				},
				"6" => {
					"id" => convenio_receita.valores_do_convenio[6].id,
					"valor" => "0"
				},
				"7" => {
					"id" => convenio_receita.valores_do_convenio[7].id,
					"valor" => "0"
				}
			}
		}
		convenio_receita.update(atributos)
		convenio_receita
	}

	it { is_expected.to belong_to :ppa }
	it { is_expected.to belong_to :unidade_orcamentaria }
	it { is_expected.to belong_to(:sub_area_tematica).class_name('Ppa::SubAreaTematica') }
	it { is_expected.to belong_to( :receita_corrente ).class_name('Projecao::Receita') }
	it { is_expected.to belong_to( :receita_de_capital ).class_name('Projecao::Receita') }

	it { is_expected.to have_many(:valores_do_convenio).dependent(:destroy).inverse_of(:convenio) }

	it { is_expected.to validate_length_of(:numero_do_convenio).is_at_most(10)}

	[:ppa_id, :objeto, :valor, :status].each { |atributo|
		it { is_expected.to validate_presence_of atributo }
	}


	describe 'criar convenios com ao menos um tipo de receita' do
		context 'salvando sem nenhum receita' do
			it 'retorna erro' do
				convenio = FactoryBot.build(:ppa_convenio, receita_corrente_id: '', receita_de_capital_id: '')
				convenio.save
				expect(convenio.errors[:receita_corrente_id]).to include "No mínimo uma receita corrente ou de capital deve ser escolhida."
				expect(convenio.errors[:receita_de_capital_id]).to include "No mínimo uma receita corrente ou de capital deve ser escolhida."
			end
		end

		context 'salvar com ao menos uma receita' do
			it 'salva convênio' do
				receita = FactoryBot.create(:receita_corrente)
				convenio = FactoryBot.build(:ppa_convenio, receita_corrente_id: receita.id, receita_de_capital_id: '')
				convenio.save
				expect(convenio).to be_persisted
			end
		end
	end

	describe '#categorias_das_receitas' do
		context 'caso categoria de receita seja diferente da esperada pelo campo' do
			it "retorna erro" do
				receita = FactoryBot.create(:receita_intra)

				convenio = FactoryBot.build :ppa_convenio
				convenio.receita_corrente_id = receita.id
				convenio.receita_de_capital_id = receita.id
				convenio.save

				expect(convenio.errors[:receita_corrente_id]).to include "deve ser de uma receita corrente"
				expect(convenio.errors[:receita_de_capital_id]).to include "deve ser de uma receita de capital"
			end
		end
		context 'caso categoria de receita seja a esperada pelo campo' do
			it "salva" do
				convenio = convenio_com_receita
				expect(convenio).to be_persisted
			end
		end
	end

	describe '#receita_nao_deve_ter_calculos_de_projecao_associados' do
		context 'se a receita estiver associada a um cálculo de projeção' do
			it "retorna erro" do
				receita_do_calculo = FactoryBot.build(:projecao_receita_do_calculo_de_projecao)
				receita_do_calculo.save(validate: false)
				convenio = FactoryBot.build :ppa_convenio
				convenio.receita_corrente_id = receita_do_calculo.receita.id
				convenio.save
				expect(convenio.errors[:receita_corrente_id]).to include "essa receita já foi projetada por meio de cálculo."
			end
		end
	end

	describe 'quando os valores do convênio são modificados' do
		it 'atualiza os calculos dos exercicios da receita' do
			@convenio = convenio_com_valores
			receita_corrente = @convenio.receita_corrente
			receita_de_capital = @convenio.receita_de_capital

			expect(receita_corrente.calculo_por_exercicios.find_by(exercicio: @convenio.valores_do_convenio[0].exercicio, tipo: 3).total.to_f).to eq 100
			expect(receita_de_capital.calculo_por_exercicios.find_by(exercicio: @convenio.valores_do_convenio[1].exercicio, tipo: 3).total.to_f).to eq 300
		end
	end

	describe '#criar_valores_do_convenio_para_cada_exercicio_do_ppa' do
		context 'ao criar um novo convênio' do
			it 'cria 2 valores de convênio para cada ano' do
				convenio = FactoryBot.create :ppa_convenio
				ppa = convenio.ppa
				ppa.periodo.each do |ano|
					expect(convenio.valores_do_convenio.where(exercicio: ano).size).to eq 2
				end
			end
		end
	end

	describe '#atualiza_calculo_por_exercicio_das_receitas' do
		before(:each) do
			@convenio_com_receita = convenio_com_receita
			@receita = @convenio_com_receita.receita_corrente
			@atributos =  {
				"valores_do_convenio_attributes" => {
					"0" => {
						"id" => @convenio_com_receita.valores_do_convenio[0].id,
						"valor" => "400"
					}
				}
			}
		end
		context 'ao atualizar valor do convênio' do
			it "atualiza o valor das receitas com o valor do convênio" do
				@convenio_com_receita.update!(@atributos)
				@receita.reload
				expect(@receita.total_agregado(2017)).to eq 400.0
			end
		end
		context 'ao apagar o convênio' do
			it "subtrai o valor das receitas com o valor do convênio" do
				@convenio_com_receita.update(@atributos)
				@receita.reload
				expect { @convenio_com_receita.destroy }.to change{ @receita.total_agregado(2017) }.from(400.0).to(0)
			end
		end
	end

	describe '#receitas' do
		it 'retorna array com as receitas' do
			convenio = convenio_com_receita
			receita = convenio.receita_corrente
			outra_receita = convenio.receita_de_capital
			expect(convenio.receitas).to eq [receita, outra_receita]
		end
	end

	describe '#tem_receitas?' do
		context 'não tenha receitas' do
			it "retorna falso" do
				convenio = FactoryBot.build :ppa_convenio
				convenio.receita_corrente_id =  nil
				convenio.receita_de_capital_id = nil
				convenio.save
				expect(convenio.tem_receitas?).to be_falsy
			end
		end
		context 'tenha receitas' do
			it "retorna verdadeiro" do
				convenio = convenio_com_receita
				expect(convenio.tem_receitas?).to be_truthy
			end
		end
	end

	describe 'resumo_de_previsao_de_convenios' do
		it 'retorna hash com a previsão dos convênios por unidade orçamentária' do
			convenio_valores = convenio_com_valores
			ppa = convenio_valores.ppa
			unidade_orcamentaria = convenio_valores.unidade_orcamentaria
			hash_resposta = [
				{:especificacao=>"CONV. CORRENTES", :exercicio1=>"100,00", :exercicio2=>"0,00", :exercicio3=>"0,00", :exercicio4=>"0,00", :total=>"100,00", :estilo=>{:negrito=>true}},
				{:especificacao=>"ADM", :exercicio1=>"100,00", :exercicio2=>"0,00", :exercicio3=>"0,00", :exercicio4=>"0,00", :total=>"100,00", :estilo=>{:tabulacao=>{:posicoes=>[0], :quantidade=>3}}},
				{:especificacao=>"CONV. DE CAPITAL", :exercicio1=>"300,00", :exercicio2=>"0,00", :exercicio3=>"0,00", :exercicio4=>"0,00", :total=>"300,00", :estilo=>{:negrito=>true}},
				{:especificacao=>"ADM", :exercicio1=>"300,00", :exercicio2=>"0,00", :exercicio3=>"0,00", :exercicio4=>"0,00", :total=>"300,00", :estilo=>{:tabulacao=>{:posicoes=>[0], :quantidade=>3}}},
				{:especificacao=>"TOTAL DE CONVÊNIOS", :exercicio1=>"400,00", :exercicio2=>"0,00", :exercicio3=>"0,00", :exercicio4=>"0,00", :total=>"400,00", :estilo=>{:negrito=>true}}
			]
			expect(Ppa::Convenio.resumo_de_previsao_de_convenios(ppa.id, unidade_orcamentaria.id)).to eq hash_resposta
		end
	end

	describe 'limpar_valores_se_receita_vazia_apos_atualizar' do
		it 'verifica se limpou os valores apos remover a receita corrente' do
			convenio = convenio_com_valores
			convenio.receita_corrente_id = nil
			convenio.save(validate: false)

			expect(convenio.valores_do_convenio.convenios_correntes.first.valor).to eq 0
		end

		it 'verifica se limpou os valores apos remover a receita de capital' do
			convenio = convenio_com_valores
			convenio.receita_de_capital_id = nil
			convenio.save(validate: false)

			expect(convenio.valores_do_convenio.convenios_de_capital.first.valor).to eq 0
		end
	end

	describe '#valido?' do
		context 'caso valor do convenio não seja igual aos valores inseridos por exercicio' do
			it 'retorna falso' do
				convenio = convenio_com_receita
				expect(convenio.valido?).to eq false
			end
		end

		context 'caso valor do convenio seja igual com os valores inseridos por exercicio' do
			it 'retorna verdadeiro' do
				convenio = convenio_com_valores
				expect(convenio.valido?).to eq true
			end
		end
	end

end
