require 'rails_helper'

RSpec.describe Licitacao::PessoaDoProjeto, type: :model do
	it{ is_expected.to belong_to(:projeto).required }
	it{ is_expected.to belong_to(:pessoa).required }

	it{ is_expected.to have_many(:contratados).inverse_of(:pessoa_do_projeto) }
	it{ is_expected.to have_many(:contratos).through(:contratados).with_foreign_key(:contratado_id) }
	it{ is_expected.to have_many(:itens_do_projeto_por_pessoa).dependent(:destroy) }
	it{ is_expected.to have_many(:itens_do_lote).through(:itens_do_projeto_por_pessoa) }
	it{ is_expected.to have_many(:lances) }
	it{ is_expected.to have_many(:lotes).through(:itens_do_lote) }
	it{ is_expected.to have_many(:lotes_ganhos).class_name("Licitacao::Lote") }
	it{ is_expected.to have_many(:pessoas_do_projeto_do_lote).dependent(:destroy) }

	it{ is_expected.to validate_uniqueness_of(:pessoa_id).scoped_to(:projeto_id) }

	it{ should accept_nested_attributes_for(:itens_do_projeto_por_pessoa)  }

	let(:processo) {
		FactoryBot.create :licitacao_processo, :por_lote #contém 2 lotes
	}

	let(:lote) {
		processo.lotes.last
	}

	let(:pessoa_do_projeto) {
		FactoryBot.create( :licitacao_pessoa_do_projeto,
			projeto_id: processo.id,
			pessoa_id: Base::Pessoa.find_or_create_by!( FactoryBot.attributes_for(:pessoa_juridica, nome: Faker::Name.name) ).id
		)
	}

	let(:outra_pessoa_do_projeto) {
		FactoryBot.create( :licitacao_pessoa_do_projeto,
			projeto_id: processo.id,
			pessoa_id: Base::Pessoa.find_or_create_by!( FactoryBot.attributes_for(:pessoa_juridica, nome: Faker::Name.name) ).id
		)
	}

	describe '#preenchimento_da_proposta_final_corresponde_ao_lance_final' do
		it 'valida que o valor enviado nas propostas finais é igual ao lance final' do
			# projeto = FactoryBot.create :licitacao_projeto, forma_de_agrupamento: "por_lote"
			# lote = FactoryBot.create :licitacao_lote, projeto_id: projeto.id, lances_abertos: false
			# pessoa_do_projeto = FactoryBot.create :licitacao_pessoa_do_projeto, projeto_id: projeto.id
			# item_do_lote = FactoryBot.create(:licitacao_item_do_lote, lote_id: lote.id)
			# allow_any_instance_of(Licitacao::Lote).to receive(:primeiro_colocado).and_return({pessoa_do_projeto: pessoa_do_projeto, valor: 500})
			# itens_do_projeto_por_pessoa_attributes = { "0" => {preco: 500, item_do_lote_id: item_do_lote.id, marca: "marca", final: true} }
			# # itens_do_projeto_por_pessoa_attributes = itens_do_lote.each_with_index.inject({}) {|hash, (item_do_lote, index)|
			# # 	hash.merge({index.to_s => })
			# # }
			# pessoa_do_projeto.update(itens_do_projeto_por_pessoa_attributes: itens_do_projeto_por_pessoa_attributes)
			# pending("Implementar - Nathann")
			# expect(pessoa_do_projeto).to be_valid

			pending("Validação removida")
			fail
		end
	end

	describe '#cria_pessoas_do_lote' do
		context 'quando a pessoa do projeto é salva' do
			it 'cria uma pessoas_do_projeto_do_lote pra cada lote do projeto' do
				expect(pessoa_do_projeto.pessoas_do_projeto_do_lote.count).to eq 1
			end
		end
	end


	describe do
		before(:each) do
			item_do_lote = lote.itens_do_lote.first
			FactoryBot.create :item_do_projeto_por_pessoa, item_do_lote_id: item_do_lote.id, pessoa_do_projeto_id: pessoa_do_projeto.id, preco: 5.5
			FactoryBot.create :item_do_projeto_por_pessoa, item_do_lote_id: item_do_lote.id, pessoa_do_projeto_id: outra_pessoa_do_projeto.id, preco: 4.5
		end

		describe '#valor_total' do
			it 'retorna o total da cotação daquela empresa para um pedido' do
				expect(pessoa_do_projeto.reload.valor_total).to eq 55.0
				expect(outra_pessoa_do_projeto.reload.valor_total).to eq 45.0
			end
		end

		describe '#valor_total_do_lote' do
			it 'retorna o total da cotação daquela empresa para um pedido' do
				expect(pessoa_do_projeto.reload.valor_total_do_lote(lote)).to eq 55.0
				expect(outra_pessoa_do_projeto.reload.valor_total_do_lote(lote)).to eq 45.0
			end
		end
	end

	it '#inicia_proposta' do
		pessoa_do_projeto.inicia_proposta

		expect(pessoa_do_projeto.itens_do_projeto_por_pessoa.length).to be > 0
	end

	it '#inicia_proposta_final' do
		pessoa_do_projeto.inicia_proposta
		pessoa_do_projeto.itens_do_projeto_por_pessoa.each { |ipp| ipp.marca = "teste"; ipp.preco = 9.99; ipp.save! }
		pessoa_do_projeto.reload
		pessoa_do_projeto.inicia_proposta_final

		expect(pessoa_do_projeto.itens_do_projeto_por_pessoa.length).to be > 0
	end

	describe '#proposta_preenchida?' do
		context 'quando pelo menos um lote está preenchido' do
			it 'retorna true' do
				allow(pessoa_do_projeto).to receive(:lotes).and_return(processo.lotes.first(2))
				expect(pessoa_do_projeto.proposta_preenchida?).to be_truthy
			end
		end
		context 'quando nenhum lote está preenchido' do
			it 'retorna false' do
					expect(pessoa_do_projeto.proposta_preenchida?).to be_falsey
			end
		end
	end

	describe '#lote_preenchido?' do
		# Esse método já está coberto no teste de #preenchimento_dos_itens_corresponde_a_forma_de_agrupamento
	end

	describe '#preenchimento_dos_itens_corresponde_a_forma_de_agrupamento' do
		context 'quando o projeto é por lote' do
			before(:each) do
				@projeto = FactoryBot.create :licitacao_projeto, :por_lote
				@pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto,
					projeto_id: @projeto.id,
					pessoa_id: Base::Pessoa.find_or_create_by!( FactoryBot.attributes_for(:pessoa_juridica, nome: Faker::Name.name) ).id
				)
			end
			context 'e todos os itens de um lote tem valor' do
				it 'salva' do
					itens_do_projeto_por_pessoa = @projeto.lotes.first.itens_do_lote.map { |item_do_lote|
						{
							item_do_lote_id: item_do_lote.id,
							pessoa_do_projeto_id: @pessoa_do_projeto.id,
							marca: "marca",
							preco: 10
						}
					}

					atributos = {
						itens_do_projeto_por_pessoa_attributes:
							itens_do_projeto_por_pessoa.each_with_index.inject({}) { |hash, (ipp, index)|
								hash.merge({index.to_s => ipp})
						}
					}
					@pessoa_do_projeto.update(atributos)

					expect(@pessoa_do_projeto).to be_persisted
				end
			end

			context 'e nem todos os itens de um lote tem valor' do
				it 'retorna erro' do
					itens_do_projeto_por_pessoa = itens_do_projeto_por_pessoa = [{
							item_do_lote_id: @projeto.lotes.first.itens_do_lote.first.id,
							pessoa_do_projeto_id: @pessoa_do_projeto.id,
							marca: "marca",
							preco: 10
						}]

					atributos = {
						itens_do_projeto_por_pessoa_attributes:
							itens_do_projeto_por_pessoa.each_with_index.inject({}) { |hash, (ipp, index)|
								hash.merge({index.to_s => ipp})
						}
					}

					@pessoa_do_projeto.update(atributos)

					expect(@pessoa_do_projeto.errors[:base]).to include "Todos os elementos do lote devem ser preenchidos nessa forma de agrupamento"
				end
			end
		end
		context 'quando o projeto é global' do
			before(:each) do
				@projeto = FactoryBot.create :licitacao_projeto, :global
				@pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: @projeto.id)
			end
			context 'e todos os itens do projeto tem valor' do
				it 'salva' do
					itens_do_projeto_por_pessoa = @projeto.itens_do_lote.map { |item_do_lote|
						{
							item_do_lote_id: item_do_lote.id,
							pessoa_do_projeto_id: @pessoa_do_projeto.id,
							marca: "marca",
							preco: 10
						}
					}

					atributos = {
						itens_do_projeto_por_pessoa_attributes:
							itens_do_projeto_por_pessoa.each_with_index.inject({}) { |hash, (ipp, index)|
								hash.merge({index.to_s => ipp})
						}
					}
					@pessoa_do_projeto.update(atributos)

					expect(@pessoa_do_projeto).to be_persisted
				end
			end
			context 'e nem todos os itens do projeto tem valor' do
				it 'retorna erro' do
					itens_do_projeto_por_pessoa = @projeto.itens_do_lote[1..-1].map { |item_do_lote|
						{
							item_do_lote_id: item_do_lote.id,
							pessoa_do_projeto_id: @pessoa_do_projeto.id,
							marca: "marca",
							preco: 10
						}
					}

					atributos = {
						itens_do_projeto_por_pessoa_attributes:
							itens_do_projeto_por_pessoa.each_with_index.inject({}) { |hash, (ipp, index)|
								hash.merge({index.to_s => ipp})
						}
					}

					@pessoa_do_projeto.update(atributos)

					expect(@pessoa_do_projeto.errors[:base]).to include "Todos os elementos devem ser preenchidos nessa forma de agrupamento"
				end
			end
		end
	end

	describe "#proposta_final_prenchida?" do
		context 'quando tem proposta final' do
			it 'retorna true' do
				projeto = FactoryBot.create :licitacao_projeto, status: :em_sessao
				pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: projeto.id)
				projeto.lotes.each do |lote|
					lote.itens_do_lote.each do |il|
						FactoryBot.create(:item_do_projeto_por_pessoa, item_do_lote_id: il.id, pessoa_do_projeto_id: pessoa_do_projeto.id, final: true)
					end
				end
				expect(pessoa_do_projeto.proposta_final_prenchida?).to be_truthy
			end
		end
		context 'quando não tem proposta final' do
			it 'retorna false' do
				projeto = FactoryBot.create :licitacao_projeto, status: :em_sessao
				pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: projeto.id)
				projeto.lotes.each do |lote|
					lote.itens_do_lote.each do |il|
						FactoryBot.create(:item_do_projeto_por_pessoa, item_do_lote_id: il.id, pessoa_do_projeto_id: pessoa_do_projeto.id)
					end
				end
				expect(pessoa_do_projeto.proposta_final_prenchida?).to be_falsey
			end
		end
	end

	describe "#descredenciar_e_desclassificar" do
		it "descredencia com justificativa e desclassifica com justificativa automática a pessoa do projeto" do
			projeto = FactoryBot.create :licitacao_projeto, status: :em_sessao
			pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: projeto.id)
			pessoa_do_projeto.descredenciar_e_desclassificar("Justificativa teste")
			expect(pessoa_do_projeto.credenciado?).to be_falsey
			expect(pessoa_do_projeto.justificativa_descredenciado).to eq "Justificativa teste"
			expect(pessoa_do_projeto.classificado?).to be_falsey
			expect(pessoa_do_projeto.justificativa_desclassificado).to eq "Desclassificado automaticamente por descredenciamento."
		end
	end

	describe "#desclassificar" do
		it "desclassifica com justificativa a pessoa do projeto e invalida suas propostas" do
			projeto = FactoryBot.create :licitacao_projeto, status: :em_sessao
			pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: projeto.id)
			pessoa_do_projeto.inicia_proposta
			pessoa_do_projeto.itens_do_projeto_por_pessoa.each { |ipp| ipp.marca = "teste"; ipp.preco = 9.99; ipp.save! }
			propostas_validas = pessoa_do_projeto.itens_do_projeto_por_pessoa.all? {|ipp| ipp.valido?}
			expect(propostas_validas).to be_truthy

			pessoa_do_projeto.desclassificar("Justificativa teste")
			pessoa_do_projeto.itens_do_projeto_por_pessoa.reload
			expect(pessoa_do_projeto.classificado?).to be_falsey
			expect(pessoa_do_projeto.justificativa_desclassificado).to eq "Justificativa teste"
			propostas_invalidas = pessoa_do_projeto.itens_do_projeto_por_pessoa.all? {|ipp| !ipp.valido?}
			expect(propostas_invalidas).to be_truthy
		end
	end

	describe "#reject_itens_do_projeto_por_pessoa" do
		let(:ipp){
			FactoryBot.create :item_do_projeto_por_pessoa
		}

		context "quando o preco é valido" do
			it "com preço valendo 10" do
				itens_do_projeto_por_pessoa_attributes = { "0" => {preco: 10, item_do_lote_id: ipp.item_do_lote.id, marca: ipp.marca, final: false} }
				pessoa_do_projeto.update(itens_do_projeto_por_pessoa_attributes: itens_do_projeto_por_pessoa_attributes)
				expect(pessoa_do_projeto.itens_do_projeto_por_pessoa.empty?).to be_falsey
			end
		end

		context "quando o preco é invalido" do
			it "com preço valendo 0" do
				itens_do_projeto_por_pessoa_attributes = { "0" => {preco: 0, item_do_lote_id: ipp.item_do_lote.id, marca: ipp.marca, final: false} }
				pessoa_do_projeto.update(itens_do_projeto_por_pessoa_attributes: itens_do_projeto_por_pessoa_attributes)
				expect(pessoa_do_projeto.itens_do_projeto_por_pessoa.empty?).to be_truthy
			end
			it "com preço vazio" do
				itens_do_projeto_por_pessoa_attributes = { "0" => {preco: "", item_do_lote_id: ipp.item_do_lote.id, marca: ipp.marca, final: false} }
				pessoa_do_projeto.update(itens_do_projeto_por_pessoa_attributes: itens_do_projeto_por_pessoa_attributes)
				expect(pessoa_do_projeto.itens_do_projeto_por_pessoa.empty?).to be_truthy
			end
		end
	end

end
