require 'rails_helper'

RSpec.describe Loa::Acao, type: :model do
	cria_tipos_de_despesa

	describe 'associations' do
		it { should belong_to(:programa_de_governo).required(true) }
		it { should belong_to(:natureza_da_acao).class_name('Base::NaturezaDaAcao').required(true) }
		it { should belong_to(:iniciativa).class_name('Ppa::Iniciativa') }
		it { should belong_to(:solicitacao_de_alteracao_orcamentaria).class_name('Contabilidade::SolicitacaoDeAlteracaoOrcamentaria') }

		it { should have_many(:subacoes).inverse_of(:acao)}
		it { should have_many(:elementos_de_despesa).through(:subacoes)}
		it { should have_many(:orcamentos_da_despesa).through(:subacoes)}
		it { should have_many(:dotacoes_origem).through(:solicitacao_de_alteracao_orcamentaria) }
		it { should have_many(:dotacoes_destino).through(:solicitacao_de_alteracao_orcamentaria) }

		it { should accept_nested_attributes_for(:subacoes).allow_destroy(true) }
	end

	describe 'validations' do
		[:programa_de_governo_id, :natureza_da_acao_id, :nome, :codigo, :status_do_orcamento].each do |atributo|
			it { should validate_presence_of atributo }
		end

		it { should validate_uniqueness_of(:codigo).scoped_to(:natureza_da_acao_id) }
		it { should validate_uniqueness_of(:nome).scoped_to(:programa_de_governo_id, :natureza_da_acao_id, :codigo) }

		it { should validate_length_of(:codigo).is_equal_to(3) }
		it { should validate_length_of(:nome).is_at_most(120) }
		it { should validate_length_of(:descricao).is_at_most(255) }
	end

	describe '#verifica_dependencia_subacao' do
		context 'quando orçamento trabalha com subação' do
			it 'não permite que a ação seja apagada' do
				subacao = FactoryBot.create(:subacao_1005_0001, :orcamento_2016)
				acao = subacao.acao
				expect { acao.destroy }.to raise_error(ActiveRecord::DeleteRestrictionError)
				# expect{ acao.destroy }.to change(Loa::Subacao, :count).by(0)
			end
		end
		context 'quando orçamento não trabalha com subação' do
			it 'apaga a subação' do
				subacao = FactoryBot.create(:subacao_1005_0001, :orcamento_2016)
				acao = subacao.acao
				orcamento_nao_trabalha_com_subacoes acao.programa_de_governo.orcamento
				expect{ acao.destroy }.to change(Loa::Subacao, :count).by(-1)
			end
		end
	end

	describe 'importado_do_ppa?' do
		it 'foi importado do ppa' do
			acao = Loa::Acao.new(iniciativa_id: 1)
			expect(acao.importado_do_ppa?).to eq true
		end

		it 'não foi importado do ppa' do
			acao = Loa::Acao.new(iniciativa_id: nil)

			expect(acao.importado_do_ppa?).to eq false
		end
	end

	describe '#subacao' do
		context 'quando o orçamento está configurado para trabalhar com subações' do
			it 'retorna nil' do
				orcamento = FactoryBot.create :orcamento_2016, trabalha_com_subacao: true
				programa  = FactoryBot.create(:programa_bolsa_familia, orcamento_id: orcamento.id)
				acao      = programa.acoes.create(FactoryBot.attributes_for :acao_9005)
				acao.subacoes.create(FactoryBot.attributes_for :subacao_1005_0001, :orcamento_2016)

				expect(acao.subacao).to eq nil
			end
		end
		context 'quando o orçamento está configurado para não trabalhar com subações' do
			it 'retorna a unica subação da ação' do
				orcamento = FactoryBot.create :orcamento_2016, trabalha_com_subacao: false
				programa  = FactoryBot.create(:programa_bolsa_familia, orcamento_id: orcamento.id)
				acao      = programa.acoes.create(FactoryBot.attributes_for :acao_9005)
				subacao   = acao.subacoes.create(FactoryBot.attributes_for :subacao_1005_0001, :orcamento_2016)
				expect(acao.subacao).to eq subacao
			end
		end
	end

	describe "#codigo_e_nome" do
		it "retorna XXXX - ACAO, onde XXXX é o código da ação e ACAO é o nome da ação" do
			acao = FactoryBot.create(:acao_9001, :orcamento_2016)
			expect( acao.codigo_e_nome ).to eq ('3.001 - CONTRATAÇÃO DE MATERIAL PARA RECURSOS HUMANOS')
		end
	end

	describe ".sugestao_de_codigo" do
		context "quando não há ações cadastradas" do
			it "retorna 001" do
				natureza_da_acao = FactoryBot.create( :natureza_projeto)
				FactoryBot.create( :programa_bolsa_familia, :orcamento_2016 )

				expect( Loa::Acao.sugestao_de_codigo(natureza_da_acao.id) ).to eq '001'
			end
		end

		context "quando há ações cadastradas" do
			it "retorna o próximo código" do
				acao_001 = FactoryBot.create( :acao_9001, :orcamento_2016, codigo: '001' )

				expect( Loa::Acao.sugestao_de_codigo(acao_001.natureza_da_acao.id) ).to eq '002'
			end
		end

		context "quando há lacunas na sequência dos códigos" do
			it "retorna a primeira lacuna" do
				acao_001 = FactoryBot.create(:acao_9001, :orcamento_2016, codigo: '001')
				FactoryBot.create(:acao_9001, :orcamento_2016, codigo: '003')
				FactoryBot.create(:acao_9001, :orcamento_2016, codigo: '005')

				expect( Loa::Acao.sugestao_de_codigo( acao_001.natureza_da_acao.id) ).to eq '002'
			end
		end
	end

	describe '#valor_total_fixado_da_despesa' do
		it "retorna o valor total fixado das subações de uma ação" do
			subacao = FactoryBot.create :subacao_1005_0001, :orcamento_2016
			acao = subacao.acao
			outra_subacao = FactoryBot.create :subacao_1005_0002, :orcamento_2016, acao_id: acao.id
			elemento_id = Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo) ).id
			fonte_id = Base::FonteDeRecursos.find_or_create_by!( FactoryBot.attributes_for(:taxas_vinculadas) ).id

			atributos_de_elementos_de_despesa_por_subacao =  {
				fixacao_da_despesa: 100.00,
				elementos_de_despesa_por_subacao_attributes: {
					"0" => {
						elemento_de_despesa_id: elemento_id,
						orcamentos_da_despesa_attributes: {
							"0" => {
								valor: 100.00,
								fonte_de_recursos_id: fonte_id
							}
						}
					}
				}
			}
			subacao.update(atributos_de_elementos_de_despesa_por_subacao)

			atributos_de_elementos_de_despesa_por_subacao =  {
				fixacao_da_despesa: 50.00,
				elementos_de_despesa_por_subacao_attributes: {
					"0" => {
						elemento_de_despesa_id: elemento_id,
						orcamentos_da_despesa_attributes: {
							"0" => {
								valor: 50.00,
								fonte_de_recursos_id: fonte_id
							}
						}
					}
				}
			}
			outra_subacao.update(atributos_de_elementos_de_despesa_por_subacao)

			expect(acao.valor_total_fixado_da_despesa).to eq 150.0
		end
	end

	describe '#valor_total_realizado_da_despesa' do
		it "retorna a soma dos valores arrecadados dos orçamentos da despesa" do
			orcamento_da_saude = Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_educacao, valor: 150.0 ) )
			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_saude, valor: 130.0, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save(validate: false)
			orcamento_da_educacao = Loa::OrcamentoDaDespesa.create( FactoryBot.attributes_for( :orcamento_da_despesa_saude, valor: 50.0 ) )
			empenho = FactoryBot.build( :empenho_22090001, orcamento_da_despesa: orcamento_da_educacao, valor: 30.0, status: :confirmado, descriminacao_obrigatoria_de_itens: false )
			empenho.save(validate: false)

			acao = orcamento_da_saude.elemento_de_despesa_por_subacao.subacao.acao
			expect(acao.valor_total_realizado_da_despesa).to eq 160.0
		end
	end

	it '#importar_dados_da_iniciativa' do

		iniciativa = FactoryBot.create( :ppa_iniciativa_para_ensino_fundamental, codigo: '001' )
		acao = FactoryBot.build(:acao_9005, :orcamento_2016, iniciativa_id: iniciativa.id)
		acao.importar_dados_da_iniciativa

		orcamento = acao.programa_de_governo.orcamento

		natureza_da_acao_id = orcamento.naturezas_da_acao.find_by(codigo: iniciativa.natureza_da_iniciativa.codigo).id

		expect(acao.attributes).to include("nome" => iniciativa.descricao[0..119], "codigo" => iniciativa.codigo_com_zeros, "descricao" => iniciativa.descricao, "natureza_da_acao_id" => natureza_da_acao_id)
	end
end
