require 'rails_helper'

RSpec.describe Licitacao::ItemDoPedido, type: :model do
	cria_configuracao_default

	subject { FactoryBot.create(:item_do_pedido) }

	it{ is_expected.to belong_to(:item).class_name('Base::Item') }

	it{ is_expected.to have_many(:itens_do_pedido_por_unidade_orcamentaria).inverse_of(:item_do_pedido).dependent(:destroy) }
	it { is_expected.to have_one(:item_do_lote) }

	it { is_expected.to accept_nested_attributes_for(:itens_do_pedido_por_unidade_orcamentaria).allow_destroy(true) }
	it { is_expected.to validate_presence_of(:item_id) }

	it { is_expected.to validate_presence_of(:tipo) }


	describe "validate_presence_of motivo" do
		subject(:licitacao_item_do_pedido_por_pessoa) {
			Licitacao::ItemDoPedido.new (FactoryBot.attributes_for(:item_do_pedido, valido: false, motivo: "Preço alto"))
		}
		it{ is_expected.to validate_presence_of(:motivo) }
	end

	describe '#classifica_valores_dos_itens' do
		it 'retorna os menores valores do item de acordo com o parâmetro' do
			item_do_pedido = FactoryBot.create(:item_do_pedido)
			FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
				item_do_pedido: item_do_pedido,
				pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
					FactoryBot.attributes_for(:pessoa_do_pedido,
						pessoa: FactoryBot.create(:pessoa_juridica,
						nome: Faker::Name.name,
						cnpj: "28052399000173"))
					)
				)
			FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
				item_do_pedido: item_do_pedido,
				pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
					FactoryBot.attributes_for(:pessoa_do_pedido,
						pessoa: FactoryBot.create(:pessoa_juridica,
						nome: Faker::Name.name,
						cnpj: "48155418000102"))
					)
				)
			FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
				item_do_pedido: item_do_pedido,
				pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
					FactoryBot.attributes_for(:pessoa_do_pedido,
						pessoa: FactoryBot.create(:pessoa_juridica,
						nome: Faker::Name.name,
						cnpj: "43001411000104"))
					)
				)

			expect( item_do_pedido.classifica_valores_dos_itens(3).size ).to eq 3
			expect( item_do_pedido.classifica_valores_dos_itens(3) ).to include(9.99)
		end
	end

		describe '#update' do
			it 'validate_uniqueness_of item no escopo de pedido' do
				item = Base::Item.find_or_create_by(FactoryBot.attributes_for :caderno, descricao: "item")

				pedido = FactoryBot.create :pedido
				pedido.itens_do_pedido.build(item_id: item.id)
				pedido.itens_do_pedido.build(item_id: item.id)
				pedido.save

				expect(pedido.errors[:itens_do_pedido]).to include("item deve ser único dentro de um pedido")
			end
		end

		describe '#quantidade_total_requisitada' do
			it 'retorna a soma das quantidades de todas as unidades' do
				item_do_pedido = FactoryBot.create :item_do_pedido #gera 10 itens no before_create
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.create(unidade_orcamentaria_por_pedido_id: Licitacao::UnidadeOrcamentariaPorPedido.maximum(:id).next, quantidade: 8)
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.create(unidade_orcamentaria_por_pedido_id: Licitacao::UnidadeOrcamentariaPorPedido.maximum(:id).next.next, quantidade: 2)
				expect(item_do_pedido.quantidade_total_requisitada).to eq 20
			end
		end

		describe '#quantidade_total_requisitada_sem_periodicidade' do
			it 'retorna a soma das quantidades de todas as unidades sem a periodicidade' do
				item_do_pedido = FactoryBot.create :item_do_pedido #gera 10 itens no before_create
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.create(unidade_orcamentaria_por_pedido_id: Licitacao::UnidadeOrcamentariaPorPedido.maximum(:id).next, quantidade: 8)
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.create(unidade_orcamentaria_por_pedido_id: Licitacao::UnidadeOrcamentariaPorPedido.maximum(:id).next.next, quantidade: 2)
				expect(item_do_pedido.quantidade_total_requisitada_sem_periodicidade).to eq 20
			end
		end

		describe '#quantidade_por_unidade_orcamentaria' do
			it 'retorna a soma das quantidades por unidade orçamentária' do
				item_da_unidade_orcamentaria = FactoryBot.build :item_da_unidade_orcamentaria #gera 10 itens no before_create
				item_da_unidade_orcamentaria.save
				item_do_pedido = item_da_unidade_orcamentaria.item_do_pedido
				expect(item_do_pedido.quantidade_por_unidade_orcamentaria(item_da_unidade_orcamentaria.unidade_orcamentaria_por_pedido.unidade_orcamentaria.id)).to eq 8
			end
		end

		describe '#quantidade_por_unidade_orcamentaria_sem_periodicidade' do
			it 'retorna a soma das quantidades por unidade orçamentária' do
				item_da_unidade_orcamentaria = FactoryBot.create :item_da_unidade_orcamentaria #gera 10 itens no before_create
				item_do_pedido = item_da_unidade_orcamentaria.item_do_pedido
				expect(item_do_pedido.quantidade_por_unidade_orcamentaria_sem_periodicidade(item_da_unidade_orcamentaria.unidade_orcamentaria_por_pedido.unidade_orcamentaria.id)).to eq 8
			end
		end

		describe '#preco_medio' do
			before(:each) do
				@item_do_pedido = FactoryBot.create :item_do_pedido
			end
			it 'calcula média dos preços dos participantes do pedido' do
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 20,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "44786806000122"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 76.41,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "08857849000198"))
						)
					)

				expect(@item_do_pedido.preco_medio).to eq  0.4214e2
			end

			it 'retorna zero quando não existe cotação' do
				expect(@item_do_pedido.preco_medio).to eq 0
			end

			context 'quando um dos preços não é válido' do
				it 'calcula a média baseada nos preços restantes' do
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 30,
						valido: false,
						motivo: "validar o teste",
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "28052399000173"))
							)
						)
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 20,
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "26368225000199"))
							)
						)
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 76.41,
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "70960420000103"))
							)
						)

					expect(@item_do_pedido.preco_medio).to eq 0.4821e2
				end
			end
		end

		describe '#total_medio' do
			it 'calcula média dos preços dos fornecedores do pedido multiplicada pela quantidade de pedidos' do
				item_do_pedido = FactoryBot.create :item_do_pedido
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 20,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "58240175000156"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 76.41,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "00365533000177"))
						)
					)
				expect(item_do_pedido.total_medio).to eq 0.4214e3
			end

			it 'retorna zero quando não existe cotação' do
				item_do_pedido = FactoryBot.create :item_do_pedido
				expect(item_do_pedido.total_medio).to eq 0
			end
		end

		describe '#menor_preco' do
			before(:each) do
				@item_do_pedido = FactoryBot.create :item_do_pedido
			end
			it 'retorna menor preço dos participantes do pedido' do
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 20,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "55138143000156"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 76.41,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "99394782000158"))
						)
					)

				expect(@item_do_pedido.menor_preco).to eq 20
			end

			it 'retorna zero quando não existe cotação' do
				expect(@item_do_pedido.menor_preco).to eq 0
			end

			context 'quando o menor preço não é válido' do
				it 'retorna o menor preço válido' do
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 30,
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "28052399000173"))
							)
						)
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 20,
						valido: false,
						motivo: "validar o teste",
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "82954461000168"))
							)
						)
					FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
						item_do_pedido: @item_do_pedido,
						preco_de_cotacao: 76.41,
						pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
							FactoryBot.attributes_for(:pessoa_do_pedido,
								pessoa: FactoryBot.create(:pessoa_juridica,
								nome: Faker::Name.name,
								cnpj: "27123663000150"))
							)
						)

					expect(@item_do_pedido.menor_preco).to eq 30
				end
			end
		end

		describe '#menor_total' do
			it 'calcula o menor dos preços dos fornecedores do pedido multiplicado pela quantidade' do
				item_do_pedido = FactoryBot.create :item_do_pedido
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 20,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "94488424000190"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 76.41,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "53375569000106"))
						)
					)
				expect(item_do_pedido.menor_total).to eq 200
			end

			it 'retorna zero quando não existe cotação' do
				item_do_pedido = FactoryBot.create :item_do_pedido

				expect(item_do_pedido.menor_total).to eq 0
			end
		end

		describe "#valor_total_projeto_simplificado" do
			it 'retorna a soma' do
				item_do_pedido = FactoryBot.create :item_do_pedido
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				item_do_pedido.update(preco_estimativo: 20)
				item_do_pedido.reload
				expect(item_do_pedido.valor_total_projeto_simplificado).to eq 200
			end
		end

		describe "#media_menores_valores_dos_itens" do
			it 'retorna o valor' do
				item_do_pedido = FactoryBot.create(:item_do_pedido)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "48155418000102"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: item_do_pedido,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "43001411000104"))
						)
					)
				expect(item_do_pedido.media_menores_valores_dos_itens(3)).to eq 9.99
			end
		end

		describe "#maior_preco" do
			before(:each) do
				@item_do_pedido = FactoryBot.create :item_do_pedido
			end
			it 'retorna maior preço dos participantes do pedido' do
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 30,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "28052399000173"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 20,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "55138143000156"))
						)
					)
				FactoryBot.create(:licitacao_item_do_pedido_por_pessoa,
					item_do_pedido: @item_do_pedido,
					preco_de_cotacao: 76.41,
					pessoa_do_pedido: Licitacao::PessoaDoPedido.find_or_create_by!(
						FactoryBot.attributes_for(:pessoa_do_pedido,
							pessoa: FactoryBot.create(:pessoa_juridica,
							nome: Faker::Name.name,
							cnpj: "99394782000158"))
						)
					)
				expect(@item_do_pedido.maior_preco).to eq 76.41
			end
		end

		describe "#periodicidade_e_unidade_de_medida" do
			it 'verificado a periocidade e uniade de media' do
				unidade_de_medida = FactoryBot.create(:percentual)
				item_do_pedido = FactoryBot.build(:item_do_pedido)
				item_do_pedido.save
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.first.update_column(:periodicidade, 2)
				expect(item_do_pedido.periodicidade_e_unidade_de_medida).to eq("2 ()")
			end

			it 'verificado a periodicidade_principal' do
				item_do_pedido = FactoryBot.create(:item_do_pedido)
				expect(item_do_pedido.periodicidade_principal).to eq( 1 )
			end
		end

		describe "#atribui_valor_previsto_ao_item" do
			it "Quando item por unidade_orcamentaria tem valor preevisto maior que zero" do
				item_do_pedido = FactoryBot.build(:item_do_pedido)
				item_do_pedido.save
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.first.update_column(:valor_previsto_desconto, 1)
				item_do_pedido.atribui_valor_previsto_ao_item
				item_do_pedido.save
				expect(item_do_pedido.por_valor_previsto?).to be_truthy
			end
			it "Quando item por unidadade orcamentaria tem valor previstor igual a zero" do
				item_do_pedido = FactoryBot.build(:item_do_pedido)
				item_do_pedido.save
				item_do_pedido.itens_do_pedido_por_unidade_orcamentaria.first.update_column(:valor_previsto_desconto, 0)
				item_do_pedido.atribui_valor_previsto_ao_item
				item_do_pedido.save
				expect(item_do_pedido.por_valor_previsto?).to be_falsey
			end
		end
end
