require 'rails_helper'

RSpec.describe Base::Categoria, type: :model do
	it { is_expected.to belong_to(:categoria_superior).class_name("Base::Categoria") }
	it { is_expected.to have_many(:subcategorias).class_name("Base::Categoria").with_foreign_key(:categoria_superior_id) }
	it { is_expected.to have_many :itens }
	it { is_expected.to have_many(:elementos_por_categoria).class_name("Base::ElementoPorCategoria") }
	it { is_expected.to have_many(:categorias_do_pedido).class_name('Licitacao::CategoriaDoPedido').dependent(:destroy) }
	it { is_expected.to have_many(:pedidos).through(:categorias_do_pedido).class_name("Licitacao::Pedido") }

	it { is_expected.to validate_presence_of :titulo }
	it { is_expected.to validate_presence_of :tipo }
	it { is_expected.to validate_presence_of :codigo }

	it { should validate_length_of(:codigo).is_at_most(3) }
	it { should validate_uniqueness_of(:codigo).scoped_to(:categoria_superior_id) }

	describe do
		subject { FactoryBot.build :categoria }
		it { is_expected.to have_many(:elementos_de_despesa).through(:elementos_por_categoria).source(:elemento_de_gasto)}
		it { is_expected.to have_many(:elementos_de_despesa_do_orcamento).through(:elementos_de_despesa).class_name("Base::ElementoDeDespesa") }

		subject { FactoryBot.build :subcategoria }
		it { is_expected.to have_many(:sub_elementos_de_despesa).through(:elementos_por_categoria).source(:elemento_de_gasto)}
		it { is_expected.to have_many(:sub_elementos_de_despesa_do_orcamento).through(:sub_elementos_de_despesa).class_name("Contabilidade::SubElementoDeDespesa") }

	end

	describe '#codigo_e_titulo' do
		it 'retorna string com codigo e titulo' do
			categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
			expect(categoria.codigo_e_titulo).to eq("12 - Categoria")
		end
	end

	describe '#categoria_e_subcategoria' do
		context 'quando não possui categoria superior' do
			it 'retorna o titulo' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria.categoria_e_subcategoria).to eq("Categoria")
			end
		end
		context 'quando possui categoria superior' do
			it 'retorna string com categoria e subcategoria' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:subcategoria)
				expect(categoria.categoria_e_subcategoria).to eq("Categoria / Categoria")
			end
		end
	end

	describe '#principal?' do
		context 'quando não possui categoria superior' do
			it 'retorna true' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria.principal?).to be_truthy
			end
		end
		context 'quando possui categoria superior' do
			it 'retorna false' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:subcategoria)
				expect(categoria.principal?).to be_falsey
			end
		end
	end

	describe '#quantidade_de_itens' do
		context 'quando ouver subcategoria' do
			it 'retorna quantidade total de itens da categoria' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				subcategoria = Base::Categoria.create FactoryBot.attributes_for(:subcategoria)
				categoria.reload
				expect(categoria.quantidade_de_itens).to eq 0
			end
		end
		context 'quando não ouver subcategoria' do
			it 'retorna quantidade total de itens' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria.quantidade_de_itens).to eq 0
			end
		end
	end

	describe '#subcategoria?' do
		context 'quando é uma categoria do primeiro nível' do
			it 'retorna false' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria.subcategoria?).to be_falsey
			end
		end
		context 'quando é uma categoria do segundo nível' do
			it 'retorna true' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				segunda_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: categoria.id)
				expect(segunda_categoria.subcategoria?).to be_truthy
			end
		end
	end

	describe '#antecessoras' do
		context 'quando é uma categoria do primeiro nível' do
			it 'retorna array vazio' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria.antecessoras).to eq []
			end
		end
		context 'quando é uma categoria do segundo nível' do
			it 'retorna array com categoria principal' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				segunda_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: categoria.id)
				expect(segunda_categoria.antecessoras).to eq [categoria]
			end
		end
	end

	describe '#filhos' do
		context 'quando é uma categoria do primeiro nível' do
			it 'retorna array com categorias' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				subcategoria = Base::Categoria.create FactoryBot.attributes_for(:subcategoria)
				categoria.reload
				expect(categoria.filhos.model).to eq Base::Categoria
			end
		end
		context 'quando é uma categoria do segundo nível' do
			it 'retorna array com categoria principal' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				segunda_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: categoria.id)
				expect(segunda_categoria.filhos.model).to eq Base::Item
			end
		end
	end

	describe '#nivel_maximo_de_categorias' do
		context 'ao criar uma categoria no primeiro nível' do
			it 'salva' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				expect(categoria).to be_persisted
			end
		end
		context 'ao criar uma categoria no segundo nível' do
			it 'salva' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				segunda_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: categoria.id)
				expect(segunda_categoria).to be_persisted
			end
		end
		context 'ao criar uma categoria no terceiro nível' do
			it 'retorna erro' do
				categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria)
				segunda_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: categoria.id)
				terceira_categoria = Base::Categoria.create FactoryBot.attributes_for(:categoria, categoria_superior_id: segunda_categoria.id)
				expect(terceira_categoria.errors[:base]).to include("Você atingiu o limite de níveis de categorias")
			end
		end
	end

	describe '#nao_deve_possuir_itens_e_categorias' do
		let(:categoria) { FactoryBot.create :categoria }
		context 'quando possui apenas itens' do
			it 'retorna verdadeiro' do
				categoria.itens.build.save(validate: false)
				expect(categoria).to be_valid
			end
		end
		context 'quando possui apenas categorias' do
			it 'retorna verdadeiro' do
				categoria.subcategorias.build.save(validate: false)
				expect(categoria).to be_valid
			end
		end
		context 'quando possui categorias e itens' do
			it 'retorna falso' do
				categoria.itens.build.save(validate: false)
				categoria.subcategorias.build.save(validate: false)
				categoria.validate
				expect(categoria.errors[:base]).to include("não pode possuir itens e categorias")
			end
		end
	end

	describe '#pode_ter_itens?' do
		let(:categoria) { FactoryBot.create :categoria }
		context 'quando não possui filhos' do
			it 'retorna verdadeiro' do
				expect(categoria.pode_ter_itens?).to be_truthy
			end
		end
		context 'quando possui itens' do
			it 'retorna verdadeiro' do
				categoria.itens.build.save(validate: false)
				expect(categoria.pode_ter_itens?).to be_truthy
			end
		end
		context 'quando possui apenas categorias' do
			it 'retorna falso' do
				categoria.subcategorias.build.save(validate: false)
				expect(categoria.pode_ter_itens?).to be_falsey
			end
		end
		context 'quando possui categorias e itens' do
			it 'retorna falso' do
				categoria.itens.build.save(validate: false)
				categoria.subcategorias.build.save(validate: false)
				categoria.validate
				expect(categoria.errors[:base]).to include("não pode possuir itens e categorias")
			end
		end
	end
end
