require 'rails_helper'

RSpec.describe Base::ElementoDeDespesa, type: :model do
	it{ is_expected.to belong_to :modalidade_de_aplicacao }

	it{ is_expected.to have_many(:sub_elementos_de_despesa).class_name('Contabilidade::SubElementoDeDespesa') }

	[:descricao, :codigo].each do |atributo|
		# it { is_expected.to validate_uniqueness_of(atributo).scoped_to :modalidade_de_aplicacao_id }  # NÃO EXISTE VALIDAÇÃO COM CONDITIONS NO SHOULDA MATCHERS
		it { is_expected.to validate_presence_of atributo }
	end

	describe "#save" do
		context "quando código ou descrição não estão contigos no seed base de naturezas da despesa" do
			context "quando não é reserva de contingência" do
				it "adiciona erros nos atributos" do
					elemento_de_despesa = Base::ElementoDeDespesa.new( codigo: '3111AA00', descricao: 'qualquer uma' )
					elemento_de_despesa.save

					expect( elemento_de_despesa.errors[:codigo] ).to include 'não existe elemento de despesa com esse código'
					expect( elemento_de_despesa.errors[:descricao] ).to include 'não existe elemento de despesa com essa descrição'
				end
			end

			context "quando é reserva de contingência" do
				it "não adiciona errors nos atributos" do
					elemento_de_despesa = Base::ElementoDeDespesa.new( codigo: '99999900', descricao: 'Reserva de Contingência' )
					elemento_de_despesa.save

					expect( elemento_de_despesa.errors[:codigo] ).to_not include 'não existe elemento de despesa com esse código'
					expect( elemento_de_despesa.errors[:descricao] ).to_not include 'não existe elemento de despesa com essa descrição'
				end
			end
		end

		context "quando código ou descrição estão contidos no seed base de naturezas da despesa'" do
			it "não adiciona erros nos atributos" do
				elemento_de_despesa = FactoryBot.create(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao)
				expect( elemento_de_despesa.errors[:codigo] ).to_not include 'não existe elemento de despesa com esse código'
				expect( elemento_de_despesa.errors[:descricao] ).to_not include 'não existe elemento de despesa com essa descrição'
			end
		end
	end

	describe "#reserva_de_contingencia?" do
		context "quando o código e nome forem 99990000 e Reserva de Contingência" do
			it "return true" do
				modalidade_de_aplicacao = Base::ModalidadeDeAplicacao.new( codigo: '99990000', descricao: 'Reserva de Contingência' )
				expect( modalidade_de_aplicacao ).to be_reserva_de_contingencia
			end
		end

		context "quando o código e nome não forem 99990000 e Reserva de Contingência" do
			it "retorna false" do
				modalidade_de_aplicacao = Base::ModalidadeDeAplicacao.new( codigo: '31000000', descricao: 'PESSOAL E ENCARGOS SOCIAIS' )
				expect( modalidade_de_aplicacao ).to_not be_reserva_de_contingencia
			end
		end
	end

	describe "#codigo_e_descricao" do
		it "retorna XXXXXXXX - DESCRIÇÃO, onde XXXXXXXX é o código e DESCRIÇÃO é a descrição" do
			elemento_de_despesa = Base::ElementoDeDespesa.new
			elemento_de_despesa.codigo = "11111111"
			elemento_de_despesa.descricao = "Descrição teste"

			expect(elemento_de_despesa.codigo_e_descricao).to eq "1.1.11.11.11 - Descrição teste"
		end
	end

	describe "#valor_total_fixado_da_despesa" do
		it "retorna a soma dos orçamentos da receita do elemento" do
			elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
			elemento_de_despesa_por_subacao = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id)
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 150.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 50.0, elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )

			expect(elemento_de_despesa.valor_total_fixado_da_despesa).to eq 200.0
		end
	end

	describe '#valor_previsto_por_mes' do
		it 'elemento sem porcentagem cadastrada retorna valor total/12' do
			elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
			elemento_de_despesa_por_subacao = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id)
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 200.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 40.0, elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )

			expect(elemento_de_despesa.valor_previsto_por_mes(1)).to eq (240/12)
		end

		it '50% cadastrado para o mes, retorna metade do valor total' do
			elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
			rcl = Base::Rcl.new(modulo_type: "Base::ElementoDeDespesa", modulo_id: elemento_de_despesa.id, percentual_janeiro: 50.0)
			rcl.save(validate: false)
			elemento_de_despesa_por_subacao = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id)
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 200.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )
			Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 40.0, elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )

			expect(elemento_de_despesa.valor_previsto_por_mes(1)).to eq (240/2)
		end
	end

	describe "#tem_folha_de_pagamento?" do
		context "quando ha folha de pagamento" do
			it "retorna true" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 1 # sim
				expect(elemento_de_despesa.tem_folha_de_pagamento?).to eq true
			end
		end

		context "quando pode ter folha de pagamento" do
			it "retorna false" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 2 # geralmente nao
				expect(elemento_de_despesa.tem_folha_de_pagamento?).to eq false
			end
		end

		context "quando nao tem folha de pagamento" do
			it "retorna false" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 0 # nao
				expect(elemento_de_despesa.tem_folha_de_pagamento?).to eq false
			end
		end
	end

	describe "#pode_ter_folha_de_pagamento?" do
		context "quando ha folha de pagamento" do
			it "retorna true" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 1 # sim
				expect(elemento_de_despesa.pode_ter_folha_de_pagamento?).to eq true
			end
		end

		context "quando pode ter folha de pagamento" do
			it "retorna true" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 3 #geralmente sim
				expect(elemento_de_despesa.pode_ter_folha_de_pagamento?).to eq true
			end
		end

		context "quando nao tem folha de pagamento" do
			it "retorna false" do
				elemento_de_despesa = FactoryBot.build :elemento_de_despesa_material_de_consumo
				elemento_de_despesa.folha_de_pagamento = 0 # nao
				expect(elemento_de_despesa.pode_ter_folha_de_pagamento?).to eq false
			end
		end
	end

	describe "#valor_total_realizado_da_despesa" do
		it "retorna a soma dos valores arrecadados orçamentos da receita do elemento" do
			elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
			elemento_de_despesa_por_subacao = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id)
			orcamento_da_despesa = Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 150.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )
			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_despesa, valor: 130.0, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save(validate: false)
			orcamento_da_despesa = Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 50.0, elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id ) )
			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_despesa, valor: 30.0, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save(validate: false)

			expect(elemento_de_despesa.valor_total_realizado_da_despesa).to eq 160.0
		end
	end

	describe "Escopo" do
		context 'intra_orcamentarios' do
			it "retorna despesas intra orçamentarias" do
				modalidade = Base::ModalidadeDeAplicacao.find_or_create_by!(FactoryBot.attributes_for(:aplicacoes_diretas))
				orcamento = Orcamento.find(modalidade.grupo_de_natureza_da_despesa.categoria_economica.modulo_id)
				elemento_de_despesa_intra = Base::ElementoDeDespesa.new( codigo: '31910000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_intra.save(validate: false)
				elemento_de_despesa_intra_capital = Base::ElementoDeDespesa.new( codigo: '31910000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_intra_capital.save(validate: false)
				elemento_de_despesa_nao_intra = Base::ElementoDeDespesa.new( codigo: '31760000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_nao_intra.save(validate: false)
				expect(orcamento.elementos_de_despesa.intra_orcamentarios).to include(elemento_de_despesa_intra)
				expect(orcamento.elementos_de_despesa.intra_orcamentarios).to include(elemento_de_despesa_intra_capital)
				expect(orcamento.elementos_de_despesa.intra_orcamentarios).not_to include(elemento_de_despesa_nao_intra)
			end
		end
		context 'exceto_intra_orcamentarios' do
			it "retorna despesas que não são intra orçamentarias" do
				modalidade = Base::ModalidadeDeAplicacao.find_or_create_by!(FactoryBot.attributes_for(:aplicacoes_diretas))
				orcamento = Orcamento.find(modalidade.grupo_de_natureza_da_despesa.categoria_economica.modulo_id)
				elemento_de_despesa_intra = Base::ElementoDeDespesa.new( codigo: '31910000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_intra.save(validate: false)
				elemento_de_despesa_nao_intra = Base::ElementoDeDespesa.new( codigo: '31760000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_nao_intra.save(validate: false)
				expect(orcamento.elementos_de_despesa.exceto_intra_orcamentarios).to include(elemento_de_despesa_nao_intra)
				expect(orcamento.elementos_de_despesa.exceto_intra_orcamentarios).not_to include(elemento_de_despesa_intra)
			end
		end
		context 'correntes_intra' do
			it "retorna despesas correntes intra orçamentarias" do
				modalidade = Base::ModalidadeDeAplicacao.find_or_create_by!(FactoryBot.attributes_for(:aplicacoes_diretas))
				orcamento = Orcamento.find(modalidade.grupo_de_natureza_da_despesa.categoria_economica.modulo_id)
				elemento_de_despesa_intra = Base::ElementoDeDespesa.new( codigo: '31910000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_intra.save(validate: false)
				elemento_de_despesa_nao_intra = Base::ElementoDeDespesa.new( codigo: '31760000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_nao_intra.save(validate: false)
				expect(orcamento.elementos_de_despesa.correntes_intra).to include(elemento_de_despesa_intra)
				expect(orcamento.elementos_de_despesa.correntes_intra).not_to include(elemento_de_despesa_nao_intra)
			end
		end
		context 'capital_intra' do
			it "retorna despesas de capital intra orçamentarias" do
				modalidade = Base::ModalidadeDeAplicacao.find_or_create_by!(FactoryBot.attributes_for(:aplicacoes_diretas))
				orcamento = Orcamento.find(modalidade.grupo_de_natureza_da_despesa.categoria_economica.modulo_id)
				elemento_de_despesa_intra = Base::ElementoDeDespesa.new( codigo: '41910000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_intra.save(validate: false)
				elemento_de_despesa_nao_intra = Base::ElementoDeDespesa.new( codigo: '31760000', descricao: 'intra_orcamentario', modalidade_de_aplicacao_id: modalidade.id)
				elemento_de_despesa_nao_intra.save(validate: false)
				expect(orcamento.elementos_de_despesa.capital_intra).to include(elemento_de_despesa_intra)
				expect(orcamento.elementos_de_despesa.capital_intra).not_to include(elemento_de_despesa_nao_intra)
			end
		end
	end

	describe '#orcamentos_da_despesa_por_unidade_orcamentaria' do
		context 'retorna o valor dos orçamentos de despesa por elemento de despesa' do
			it 'retorna valor do orçamento da despesa' do
				elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
				subacao_uo_fes = FactoryBot.create :subacao_1005_0002, :orcamento_2016
				subacao_uo_seduc = FactoryBot.create :subacao_1005_0003, :orcamento_2016
				elemento_de_despesa_por_subacao_001 = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id, subacao_id: subacao_uo_fes.id)
				elemento_de_despesa_por_subacao_002 = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id, subacao_id: subacao_uo_seduc.id)
				Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 150.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao_001.id ) )
				Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 50.0, elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao_002.id ) )
				expect(elemento_de_despesa.orcamentos_da_despesa_por_unidade_orcamentaria(subacao_uo_fes.unidade_orcamentaria.id)).to eq 150.0
			end
		end
	end

	it 'valor_previsto_por_unidade_orcamentaria' do
		elemento_de_despesa = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo, :com_modalidade_de_aplicacao) )
		subacao_uo_seduc = FactoryBot.create :subacao_1005_0003, :orcamento_2016
		elemento_de_despesa_por_subacao_001 = FactoryBot.create(:elemento_de_despesa_por_subacao, elemento_de_despesa_id: elemento_de_despesa.id, subacao_id: subacao_uo_seduc.id)
		Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 150.0 , elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao_001.id ) )
		expect(elemento_de_despesa.valor_previsto_por_unidade_orcamentaria(subacao_uo_seduc.unidade_orcamentaria.id)).to eq 150.0
	end
end
