require 'rails_helper'

RSpec.describe Loa::ProgramaDeGoverno, type: :model do
	let(:atributos_de_elementos_de_despesa_por_subacao) {
		{
			fixacao_da_despesa: 100.00,
			elementos_de_despesa_por_subacao_attributes: {
				"0" => {
					elemento_de_despesa_id: Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo) ).id,
					orcamentos_da_despesa_attributes: {
						"0" => {
							valor: 100.00,
							fonte_de_recursos_id: Base::FonteDeRecursos.find_or_create_by!( FactoryBot.attributes_for(:taxas_vinculadas) ).id
						}
					}
				}
			}
		}
	}

	let(:outros_atributos_de_elementos_de_despesa_por_subacao) {
		{
			fixacao_da_despesa: 50.00,
			elementos_de_despesa_por_subacao_attributes: {
				"0" => {
					elemento_de_despesa_id: Base::ElementoDeDespesa.find_or_create_by!( FactoryBot.attributes_for(:elemento_de_despesa_material_de_consumo) ).id,
					orcamentos_da_despesa_attributes: {
						"0" => {
							valor: 50.00,
							fonte_de_recursos_id: Base::FonteDeRecursos.find_or_create_by!( FactoryBot.attributes_for(:taxas_vinculadas) ).id
						}
					}
				}
			}
		}
	}

	it{ is_expected.to belong_to(:orcamento).required }
	it{ is_expected.to belong_to :tipo_de_programa }
	it{ is_expected.to belong_to(:programa).class_name('Ppa::Programa') }
	it{ is_expected.to have_many(:acoes).dependent(:restrict_with_exception) }
	it{ is_expected.to have_many(:subacoes).through(:acoes) }
	it{ is_expected.to have_many(:metas_fisicas).through(:subacoes) }

	it { is_expected.to validate_length_of( :codigo ).is_equal_to(4) }
	it { is_expected.to validate_length_of( :nome ).is_at_most(120) }

	[:orcamento_id, :codigo, :nome, :status_do_orcamento].each do |atributo|
		it{ is_expected.to validate_presence_of atributo }
	end
	context "Tem Programa" do
		before { allow(subject).to receive(:eh_progama?).and_return(true) }
		it{ is_expected.to validate_presence_of :tipo_de_programa_id }
	end

	it{ is_expected.to validate_uniqueness_of( :codigo ).scoped_to(:orcamento_id) }
	it{ is_expected.to validate_uniqueness_of( :nome ).scoped_to(:orcamento_id, :codigo) }

	describe '#codigo_e_nome' do
		it "retorna 'XXXX - NOME', onde XXXX é o código e NOME é o nome do programa de governo" do
			programa_de_governo = Loa::ProgramaDeGoverno.new(codigo: '2020', nome: "Programa X")
			expect(programa_de_governo.codigo_e_nome).to eq('2020 - Programa X')
		end
	end

	describe "#sugestao_de_codigo" do
		before(:each) do
			@tipo_de_programa_tematico = FactoryBot.create(:tipo_de_programa_tematico)
			@tipo_de_programa_gestao = FactoryBot.create(:tipo_de_programa_gestao)
		end
		context "quando não há programas cadastrados" do
			it "retorna 01" do
				programa_de_governo = Loa::ProgramaDeGoverno.new( FactoryBot.attributes_for( :esporte_e_lazer, :orcamento_2016, codigo: '', tipo_de_programa: @tipo_de_programa_tematico ) )

				expect(programa_de_governo.codigo).to eq '1001'
			end
		end

		context "quando há programas cadastrados" do
			it "retorna o próximo código" do
				FactoryBot.create( :programa_bolsa_familia, :orcamento_2016, codigo: '1001', tipo_de_programa: @tipo_de_programa_tematico )

				programa = Loa::ProgramaDeGoverno.create( FactoryBot.attributes_for( :minha_casa_minha_vida, :orcamento_2016, codigo: '', tipo_de_programa: @tipo_de_programa_tematico ) )

				expect(programa.codigo).to eq '1002'
			end
		end

		context "quando há lacunas na sequência dos códigos" do
			it "retorna a primeira lacuna" do
				FactoryBot.create( :programa_bolsa_familia, :orcamento_2016, codigo: '1001', tipo_de_programa: @tipo_de_programa_tematico )
				FactoryBot.create( :minha_casa_minha_vida, :orcamento_2016, codigo: '1003', tipo_de_programa: @tipo_de_programa_tematico )
				FactoryBot.create( :esporte_e_lazer, :orcamento_2016, codigo: '1005', tipo_de_programa: @tipo_de_programa_tematico )

				programa = Loa::ProgramaDeGoverno.new( FactoryBot.attributes_for( :programa_bolsa_familia, :orcamento_2016, codigo: '', tipo_de_programa: @tipo_de_programa_tematico ) )

				expect(programa.codigo).to eq '1002'
			end
		end
	end

	describe 'set_programa_de_governo_id' do
		context 'quando tem programa' do
			it 'e vincula à solicitação' do
				solicitacao = FactoryBot.create :solicitacao_de_alteracao_orcamentaria, origem_do_recurso: :anulacao_de_dotacao
				programa = FactoryBot.create(:programa_bolsa_familia, :orcamento_2016, solicitacao_de_alteracao_orcamentaria_id: solicitacao.id)
				solicitacao.reload
				expect( solicitacao.programa_de_governo_da_solicitacao_id ).to eq programa.id
			end
		end
	end

	describe '#nao_permitir_mudar_tipo_do_programa_com_porcentagem_presente'do
		it 'retorna erro' do
			programa = FactoryBot.create( :programa_bolsa_familia, :orcamento_2016)
			acao = FactoryBot.create( :acao_9005, programa_de_governo_id: programa.id )
			subacao = FactoryBot.create(:subacao_1005_0001, :orcamento_2016,acao_id: acao.id )
			FactoryBot.create(:loa_tema_da_subacao, subacao_id: subacao.id)
			tipo_de_programa = FactoryBot.create(:tipo_de_programa_gestao)

			programa.update(tipo_de_programa_id: tipo_de_programa.id)
			expect( programa.errors["tipo_de_programa_id".to_sym] ).to include( "Não é possível alterar o tipo do programa, pois existe percentual de um orçamento temático associado")

		end
		it 'permiti edição' do
			programa = FactoryBot.create( :programa_bolsa_familia, :orcamento_2016)
			acao = FactoryBot.create( :acao_9005, programa_de_governo_id: programa.id )
			subacao = FactoryBot.create(:subacao_1005_0001, :orcamento_2016,acao_id: acao.id )
			FactoryBot.create(:loa_tema_da_subacao, subacao_id: subacao.id)
			FactoryBot.create(:tipo_de_programa_gestao)

			programa.update(nome: 'teste nome')
			expect( programa.nome ).to eq 'teste nome'
		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
			programa = subacao.acao.programa_de_governo
			outra_subacao = FactoryBot.create :subacao_1005_0002, :orcamento_2016, acao_id: acao.id
			subacao.update(atributos_de_elementos_de_despesa_por_subacao)
			outra_subacao.update(outros_atributos_de_elementos_de_despesa_por_subacao)

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

	describe '#valor_total_fixado_da_despesa_por_unidade' 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
			programa = subacao.acao.programa_de_governo
			unidade = subacao.unidade_orcamentaria
			outra_subacao = FactoryBot.create :subacao_1005_0002, :orcamento_2016, acao_id: acao.id
			subacao.update(atributos_de_elementos_de_despesa_por_subacao)
			outra_subacao.update(outros_atributos_de_elementos_de_despesa_por_subacao)
			outra_unidade = outra_subacao.unidade_orcamentaria
			expect(programa.valor_total_fixado_da_despesa_por_unidade(unidade)).to eq 100.0
			expect(programa.valor_total_fixado_da_despesa_por_unidade(outra_unidade)).to eq 50.0
		end
	end

	describe '#valor_total_fixado_da_despesa_orcamentos_fiscal' do

		it "retorna o valor total fixado das subações do tipo orçamento fiscal de uma ação" do
			orcamento = FactoryBot.create :orcamento_2016
			tipo_de_orcamento = orcamento.tipos_de_orcamento.find_by( codigo: 'F' )
			subacao_social = FactoryBot.create( :subacao_1005_0001, :orcamento_2016)
			acao = subacao_social.acao
			programa = acao.programa_de_governo
			subacao_fiscal = FactoryBot.create :subacao_1005_0002, :orcamento_2016, acao_id: acao.id, tipo_de_orcamento_id: tipo_de_orcamento.id

			subacao_social.update(atributos_de_elementos_de_despesa_por_subacao)
			subacao_fiscal.update(outros_atributos_de_elementos_de_despesa_por_subacao)

			expect(programa.valor_total_fixado_da_despesa_orcamentos_fiscal).to eq 50.0
		end
	end

	describe '#valor_total_fixado_da_despesa_seguridade_social' do
		it "retorna o valor total fixado das subações do tipo seguridade social de uma ação" do
			orcamento = FactoryBot.create :orcamento_2016
			tipo_de_orcamento = orcamento.tipos_de_orcamento.find_by( codigo: 'S' )

			subacao_social = FactoryBot.create :subacao_1005_0001, :orcamento_2016, tipo_de_orcamento_id: tipo_de_orcamento.id
			acao = subacao_social.acao
			programa = acao.programa_de_governo
			subacao_fiscal = FactoryBot.create :subacao_1005_0002, :orcamento_2016, acao_id: acao.id
			subacao_social.update(atributos_de_elementos_de_despesa_por_subacao)
			subacao_fiscal.update(outros_atributos_de_elementos_de_despesa_por_subacao)

			expect(programa.valor_total_fixado_da_despesa_seguridade_social).to eq 100.0
		end
	end

	describe '#valor_total_realizado_da_despesa' do
		it 'retorna valor total realizado da despesa' do
			empenho = FactoryBot.create :empenho_22090001, valor: 20, descriminacao_obrigatoria_de_itens: false
			programa_de_governo = empenho.orcamento_da_despesa.elemento_de_despesa_por_subacao.subacao.acao.programa_de_governo
			expect(programa_de_governo.valor_total_realizado_da_despesa).to eq 20
		end
	end

	describe '#programa_tematico?' do
		context 'quando o programa é temático' do
			it 'retorna true' do
				tipo_de_programa = FactoryBot.create :tipo_de_programa_tematico
				programa = FactoryBot.create :programa_bolsa_familia, :orcamento_2017, tipo_de_programa_id: tipo_de_programa.id
				expect(programa.programa_tematico?).to be_truthy
			end
		end

		context 'quando o programa não é temático' do
			it 'retorna false' do
				tipo_de_programa = FactoryBot.create :tipo_de_programa_tematico, codigo: "2"
				programa = FactoryBot.create :programa_bolsa_familia, :orcamento_2017, tipo_de_programa_id: tipo_de_programa.id
				expect(programa.programa_tematico?).to be_falsy
			end
		end
	end

	describe 'to_sim' do
		before(:each) do
			FactoryBot.create(:configuracao)
		end
		# testar sempre validando se o ultimo campo foi preenchido
		it 'retorna string formatada para envio ao SIM' do
			unidade_orcamentaria = FactoryBot.build(:loa_hgf, :orcamento_2016)

			expect( unidade_orcamentaria.to_sim ).to eq '"104","099","201600","04","0002","91","HOSPITAL GERAL DE FORTALEZA","D"'
		end
	end

	describe 'importado_do_ppa?' do
		it 'foi importado do ppa' do
			programa_de_governo = Loa::ProgramaDeGoverno.new(programa_id: 1)
			expect(programa_de_governo.importado_do_ppa?).to eq true
		end

		it 'não foi importado do ppa' do
			programa_de_governo = Loa::ProgramaDeGoverno.new(programa_id: nil)

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

	it 'importar_dados_do_programa' do
		programa = FactoryBot.create( :programa_escolar, :ppa_2014 )
		programa_de_governo = Loa::ProgramaDeGoverno.new(programa_id: programa.id)
		programa_de_governo.importar_dados_do_programa

		expect(programa_de_governo.attributes).to include("nome" => programa.nome, "codigo" => programa.codigo_completo, "objetivo" => programa.justificativa, "tipo_de_programa_id" => programa.tipo_de_programa_id)
	end
end
