
require 'rails_helper'

RSpec.describe Loa::ElementoDeDespesaPorSubacao, type: :model do
	it{ is_expected.to belong_to(:subacao).required }
	it{ is_expected.to belong_to( :elemento_de_despesa ).class_name('Base::ElementoDeDespesa').required }

	it{ is_expected.to have_many(:orcamentos_da_despesa).dependent(:destroy).inverse_of(:elemento_de_despesa_por_subacao) }

	it{ is_expected.to accept_nested_attributes_for(:orcamentos_da_despesa).allow_destroy(true)}

	it{ is_expected.to validate_presence_of :subacao_id }
	it{ is_expected.to validate_presence_of :elemento_de_despesa_id }

	describe 'validates_uniqueness_of' do
		it 'validate_uniqueness_of elemento_de_despesa_id no escopo subacao_id' do
			subacao = FactoryBot.create :subacao_1005_0002, :orcamento_2016
			elemento_de_despesa = FactoryBot.create :elemento_de_despesa_material_de_consumo
			FactoryBot.create :alienacao_de_bens

			atributos_de_elementos_de_despesa_por_subacao =  {
				elementos_de_despesa_por_subacao_attributes: {
					"0" => {
						elemento_de_despesa_id: elemento_de_despesa.id,
					},
					"1" => {
						elemento_de_despesa_id: elemento_de_despesa.id,
					},
				}
			}

			subacao.update(atributos_de_elementos_de_despesa_por_subacao)

			expect(
				subacao.errors[:"elementos_de_despesa_por_subacao"][0]
			).to include( 'elemento de despesa deve ser único dentro da subação' )
		end
	end

	describe "#valor_total" do
		before do
			Base::TipoDeOrcamento.find_or_create_by!( FactoryBot.attributes_for( :seguridade_social, :orcamento_2016 ) )
		end
		it "retorna a soma dos orçamentos da receita" do
			elemento_de_despesa_por_subacao = FactoryBot.create(:elemento_de_despesa_por_subacao)
			FactoryBot.create(:orcamento_da_despesa_saude)
			FactoryBot.create(:orcamento_da_despesa_educacao)

			expect(elemento_de_despesa_por_subacao.valor_total).to eq(12365.67)
		end
	end

	describe "#update" do
		before do
			@subacao = FactoryBot.create(:subacao_1005_0001, :orcamento_2016)
			@elemento_de_despesa = FactoryBot.create :elemento_de_despesa_material_de_consumo
			@fonte_de_recursos = FactoryBot.create :alienacao_de_bens
			@fonte_de_recursos_diferente = FactoryBot.create :alienacao_de_bens, codigo: "99", descricao: "Descrição diferente."
		end

		context "quando são passados fonte de recursos repetidos" do
			it "retorna mensagem de erro" do
				atributos_de_elementos_de_despesa_por_subacao =  {
					elementos_de_despesa_por_subacao_attributes: {
						"0" => {
							elemento_de_despesa_id: @elemento_de_despesa.id,
							orcamentos_da_despesa_attributes: {
								"0" => {
									fonte_de_recursos_id: @fonte_de_recursos.id,
									valor: 9.99
								},
								"1" => {
									fonte_de_recursos_id: @fonte_de_recursos.id,
									valor: 8.73
								}
							}
						}
					}
				}

				@subacao.update( atributos_de_elementos_de_despesa_por_subacao )
				expect( @subacao.errors["elementos_de_despesa_por_subacao.orcamentos_da_despesa".to_sym] ).to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
				expect( @subacao.elementos_de_despesa_por_subacao.first.orcamentos_da_despesa.first.errors[:fonte_de_recursos_id] ).not_to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
				expect( @subacao.elementos_de_despesa_por_subacao.first.orcamentos_da_despesa.last.errors[:fonte_de_recursos_id] ).to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
			end
		end

		context "quando não são passados fonte de recursos repetidos" do
			it "atualiza subacao" do
				atributos_de_elementos_de_despesa_por_subacao =  {
					elementos_de_despesa_por_subacao_attributes: {
						"0" => {
							elemento_de_despesa_id: @elemento_de_despesa.id,
							orcamentos_da_despesa_attributes: {
								"0" => {
									fonte_de_recursos_id: @fonte_de_recursos.id,
									valor: 9.99
								},
								"1" => {
									fonte_de_recursos_id: @fonte_de_recursos_diferente.id,
									valor: 8.73
								}
							}
						}
					}
				}

				@subacao.update( atributos_de_elementos_de_despesa_por_subacao )
				expect( @subacao.errors["elementos_de_despesa_por_subacao.orcamentos_da_despesa".to_sym] ).not_to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
				expect( @subacao.elementos_de_despesa_por_subacao.first.orcamentos_da_despesa.first.errors[:fonte_de_recursos_id] ).not_to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
				expect( @subacao.elementos_de_despesa_por_subacao.first.orcamentos_da_despesa.last.errors[:fonte_de_recursos_id] ).not_to include( 'fonte de recursos deve ser único dentro de elemento de despesa' )
			end
		end

		context '#despesa_reserva_de_contingencia_deve_ser_unidade_reserva_de_contingencia' do
			it 'retorna mensagem de erro, caso a unidade orçamentaria daquela despesa não seja do tipo reserva de contingencia' do
				elemento_de_despesa_reserva = Base::ElementoDeDespesa.create!( codigo: '99999900', descricao: 'Reserva de Contingência', modalidade_de_aplicacao_id: 1 )

				atributos_de_elementos_de_despesa_por_subacao =  {
					elementos_de_despesa_por_subacao_attributes: {
						"0" => {
							elemento_de_despesa_id: elemento_de_despesa_reserva.id,
						}
					}
				}

				@subacao.update( atributos_de_elementos_de_despesa_por_subacao )
				expect( @subacao.errors["elementos_de_despesa_por_subacao.elemento_de_despesa_id".to_sym] ).to include( 'só pode ser selecionada se o orgão, a unidade orçamentária, a função e a subfunção forem do tipo reserva de contingência' )
			end
		end

		context "quando total fixado não corresponde ao valor passado" do
			it "retorna mensagem de erro" do
				atributos_de_elementos_de_despesa_por_subacao =  {
					fixacao_da_despesa: 20,
					elementos_de_despesa_por_subacao_attributes: {
						"0" => {
							elemento_de_despesa_id: @elemento_de_despesa.id,
							orcamentos_da_despesa_attributes: {
								"0" => {
									fonte_de_recursos_id: @fonte_de_recursos.id,
									valor: 9.99
								},
								"1" => {
									fonte_de_recursos_id: @fonte_de_recursos_diferente.id,
									valor: 8.73
								}
							}
						}
					}
				}

				@subacao.update( atributos_de_elementos_de_despesa_por_subacao )
				expect( @subacao.errors[:fixacao_da_despesa] ).to include('valor da fixação não corresponde ao total da despesa')
			end
		end
	end
end
