require 'rails_helper'

RSpec.describe Licitacao::Lance, type: :model do
	it { is_expected.to belong_to(:rodada) }
	it { is_expected.to belong_to(:pessoa_do_projeto) }

	it { is_expected.to validate_presence_of :rodada_id }
	it { is_expected.to validate_presence_of :pessoa_do_projeto_id }
	it { is_expected.to validate_numericality_of( :valor ).is_greater_than(0) }

	before(:each) do
		allow_any_instance_of(Licitacao::Rodada).to receive(:todos_os_itens_do_lote_devem_ter_cotacoes).and_return(true)
		FactoryBot.reload
	end

	describe "validate_absence_of valor" do
		subject(:licitacao_lance) {
			FactoryBot.build(:licitacao_lance, desistir: true)
		}
		it{ is_expected.to validate_absence_of(:valor) }

	end

	describe "validates_presence_of valor" do
		subject(:licitacao_lance) {
			FactoryBot.build(:licitacao_lance, desistir: false)
		}
		it{ is_expected.to validate_presence_of(:valor) }
	end

	let(:lote) {
		projeto = FactoryBot.create(:licitacao_projeto, :por_lote)
		lote = projeto.lotes.last
		lote.update(lances_abertos: true)
		lote
	}

	let(:item) {
		projeto = FactoryBot.create(:licitacao_projeto, :por_item)
		lote_item = projeto.lotes.last
		lote_item.update(lances_abertos: true)
		lote_item
	}

	describe '#valor_anterior' do
		context 'quando o projeto é por lote' do

			context 'e o lance é da primeira rodada' do
				it 'retorna valor referente ao lance inicial' do
					rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
					lance = rodada.lances.first

					expect(lance.valor_anterior).to eq 399.6
				end
			end

			context 'e o lance é de segunda rodada' do
				it 'retorna valor referente à primeira rodada' do
					primeira_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
					primeira_rodada.lances.update_all(valor: 10)
					primeira_rodada.reload

					segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
					lance = segunda_rodada.lances.first

					expect(lance.valor_anterior).to eq primeira_rodada.lances.first.valor
				end
			end
		end

		context 'quando o projeto é por item' do
			context 'quando o lance é da primeira rodada' do
				it 'retorna valor referente ao lance inicial' do
					rodada = FactoryBot.create(:licitacao_rodada, lote: item)
					lance = rodada.lances.first
					expect(lance.valor_anterior).to eq 9.99
				end
			end

			context 'quando o lance é de segunda rodada' do
				it 'retorna valor referente à primeira rodada' do
					primeira_rodada = FactoryBot.create(:licitacao_rodada, lote: item)
					primeira_rodada.lances.update_all(valor: 10)
					primeira_rodada.reload
					segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: item)
					lance = segunda_rodada.lances.first
					expect(lance.valor_anterior).to eq primeira_rodada.lances.first.valor
				end
			end
		end
	end

	describe '#menor_valor_da_rodada_anterior' do
		context 'quando o projeto é por lote' do
			it 'retorna o menor valor da última rodada (multiplicado pela quantidade)' do
				primeira_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
				expect(primeira_rodada.lances.first.menor_valor_da_rodada_anterior).to eq 199.8
			end
		end

		context 'quando o projeto é por item' do
			it 'retorna o menor valor da última rodada (apenas o valor do lance)' do
				primeira_rodada = FactoryBot.create(:licitacao_rodada, lote: item)
				primeira_rodada.lances.update_all(valor: 10)

				segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: item)
				segunda_rodada.lances.first.update!(valor: 9)
				segunda_rodada.reload
				expect(segunda_rodada.lances.first.menor_valor_da_rodada_anterior).to eq 10
			end
		end
	end

	describe '#deve_ser_menor_que_o_menor_valor_da_rodada_anterior' do
		context 'quando o projeto é por lote' do
			let(:rodada) { FactoryBot.create(:licitacao_rodada, lote: lote) }

			context 'quando o lance percente à primeira rodada' do
				context 'e é maior que o valor anterior' do
					it 'retorna erro' do
						lance = rodada.lances.first

						lance.update(valor: 200)

						expect(lance.errors[:valor]).to include "deve ser menor que o menor valor da oferta inicial"
					end
				end

				context 'e é igual ao valor anterior' do
					it 'retorna erro' do
						lance = rodada.lances.first
						lance.update(valor: lance.valor_anterior)
						expect(lance.errors[:valor]).to include "deve ser menor que o menor valor da oferta inicial"
					end
				end

				context 'e é menor que o valor anterior' do
					it 'atualiza lance' do
						lance = rodada.lances.first
						lance.update(valor: 10)

						expect(lance.reload.valor).to eq 10
					end
				end
			end

			context 'quando o lance percente à segunda rodada' do
				before(:each) do
					rodada.lances.update_all(valor: 10)
				end

				context 'quando o lance é maior que o valor anterior' do
					it 'retorna erro' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 14)

						expect(lance.errors[:valor]).to include "deve ser menor que o menor lance da rodada anterior"
					end
				end

				context 'quando o lance é igual ao valor anterior' do
					it 'retorna erro' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 10)

						expect(lance.errors[:valor]).to include "deve ser menor que o menor lance da rodada anterior"
					end
				end

				context 'quando o lance é menor que o valor anterior' do
					it 'salva valor' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 8)

						expect(lance.reload.valor).to eq 8
					end
				end
			end
		end

		context 'quando o projeto é por item' do
			let(:rodada) { FactoryBot.create(:licitacao_rodada, lote: item) }
			let(:lance) { rodada.lances.first } # valor_anterior: 19.98

			before(:each) do
				rodada.lances.update_all(valor: 10)
			end

			context 'quando o lance percente à primeira rodada' do
				context 'e é maior que o valor anterior' do
					it 'retorna erro' do
						#Não cria lance quando o lote é por item
						lance.update(valor: 20)
						expect(lance.errors[:valor]).to include "deve ser menor que o menor valor da oferta inicial"
					end
				end

				context 'e é igual ao valor anterior' do
					it 'retorna erro' do
						lance.update(valor: 19.98)
						expect(lance.errors[:valor]).to include "deve ser menor que o menor valor da oferta inicial"
					end
				end

				context 'e é menor que o valor anterior' do
					it 'atualiza lance' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: item)
						segunda_rodada.lances.first.update(valor: 9)
						segunda_rodada.reload
						expect(segunda_rodada.lances.first.valor).to eq 9
					end
				end
			end

			context 'para a segunda rodada' do
				let(:segunda_rodada) { FactoryBot.create(:licitacao_rodada, lote: item) }
				let(:lance) { segunda_rodada.lances.first }

				before(:each) do
					rodada.lances.update_all(valor: 10)
				end

				context 'quando o lance é maior que o valor anterior' do
					it 'retorna erro' do
						lance.update(valor: 14)
						expect(lance.errors[:valor]).to include "deve ser menor que o menor lance da rodada anterior"
					end
				end

				context 'quando o lance é igual ao valor anterior' do
					it 'retorna erro' do
						lance.update(valor: lance.valor_anterior)
						expect(lance.errors[:valor]).to include "deve ser menor que o menor lance da rodada anterior"
					end
				end

				context 'quando o lance é menor que o valor anterior' do
					it 'salva valor' do
						lance.update(valor: 8)
						expect(lance.reload.valor).to eq 8
					end
				end
			end
		end
	end

	describe '#preenche_valor_com_valor_anterior' do
		let(:lance) { FactoryBot.build(:licitacao_lance) }
		context 'quando valor está vazio' do
			context 'quando lance_final = true' do
				it 'salva lance com o mesmo valor anterior' do
					allow(lance).to receive(:valor_anterior).and_return(100)
					lance.lance_final = true
					lance.valor = nil
					lance.validate
					expect(lance).to be_valid
					expect(lance.valor).to eq 100
				end
			end
			context 'quando lance_final = false' do
				it 'retorna erro ' do
					allow(lance).to receive(:valor_anterior).and_return(100)
					lance.lance_final = false
					lance.valor = nil
					lance.validate
					expect(lance).not_to be_valid
				end
			end
		end
	end

	describe '#deve_ser_maior_que_o_maior_valor_da_rodada_anterior' do
		context 'quando o lote é por desconto' do
			let(:rodada) { FactoryBot.create(:licitacao_rodada, lote: lote) }

			before(:each) do
				rodada.lote.itens_do_lote.each {|il| il.item_do_pedido.por_desconto!}
			end

			context 'quando o lance percente à primeira rodada' do
				context 'e é menor que o valor anterior' do
					it 'retorna erro' do
						lance = rodada.lances.first

						lance.update(valor: -1)

						expect(lance.errors[:valor].to_s).to include "deve ser maior que o maior valor da oferta inicial"
					end
				end

				context 'e é igual ao valor anterior' do
					it 'retorna erro' do
						lance = rodada.lances.first
						lance.update(valor: lance.valor_anterior)
						expect(lance.errors[:valor]).to include "deve ser maior que o maior valor da oferta inicial"
					end
				end

				context 'e é maior que o valor anterior' do
					it 'atualiza lance' do
						lance = rodada.lances.first
						lance.update(valor: 50)

						expect(lance.reload.valor).to eq 50
					end
				end
			end

			context 'quando o lance percente à segunda rodada' do
				before(:each) do
					rodada.lances.update_all(valor: 10)
				end

				context 'quando o lance é menor que o valor anterior' do
					it 'retorna erro' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 9)

						expect(lance.errors[:valor]).to include "deve ser maior que o maior lance da rodada anterior"
					end
				end

				context 'quando o lance é igual ao valor anterior' do
					it 'retorna erro' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 10)

						expect(lance.errors[:valor]).to include "deve ser maior que o maior lance da rodada anterior"
					end
				end

				context 'quando o lance é maior que o valor anterior' do
					it 'salva valor' do
						segunda_rodada = FactoryBot.create(:licitacao_rodada, lote: lote)
						lance = segunda_rodada.lances.first
						lance.update(valor: 12)

						expect(lance.reload.valor).to eq 12
					end
				end
			end
		end
	end

end
