require 'rails_helper'

RSpec.describe Contabilidade::Obra, type: :model do

	it{ is_expected.to belong_to(:orcamento).required(true) }
	it{ is_expected.to belong_to :cidade }
	it{ is_expected.to belong_to(:tipo_de_administracao).class_name('Base::TipoDeAdministracao').required(true) }
	it{ is_expected.to belong_to(:contrato).class_name('Licitacao::Contrato').required(true) }
	it{ is_expected.to belong_to(:contrato_estudos).class_name('Licitacao::Contrato').with_foreign_key(:contrato_estudos_id) }
	it{ is_expected.to belong_to(:classificacao_do_bem).class_name('Contabilidade::Conta').with_foreign_key(:conta_id) }
	it{ is_expected.to belong_to(:conta_pcasp).class_name('Contabilidade::Conta').with_foreign_key(:conta_pcasp_id) }

	it{ is_expected.to have_many(:engenheiros_da_obra).dependent(:restrict_with_exception) }
	it{ is_expected.to have_many(:empresas_da_obra).dependent(:restrict_with_exception) }
	it{ is_expected.to have_many(:situacoes_da_obra).dependent(:destroy) }
	it{ is_expected.to have_many(:ordens_de_servico).dependent(:restrict_with_exception) }
	it{ is_expected.to have_many(:documentos_da_obra).dependent(:destroy) }
	it{ is_expected.to have_many(:contratos_da_obra).dependent(:destroy) }
	it{ is_expected.to have_many(:fiscalizacoes).dependent(:destroy) }
	it{ is_expected.to have_many(:garantias_da_obra).dependent(:destroy) }
	it{ is_expected.to have_many(:transferencias).dependent(:destroy) }
	it{ is_expected.to have_many(:operacoes_de_credito).dependent(:destroy) }

	it { is_expected.to validate_length_of(:cep).is_equal_to(8) }
	it { is_expected.to validate_length_of(:logradouro).is_at_most(120) }
	it { is_expected.to validate_length_of(:numero_logradouro).is_at_most(8) }
	it { is_expected.to validate_length_of(:complemento).is_at_most(80) }
	it { is_expected.to validate_length_of(:bairro).is_at_most(60) }

	[
		:orcamento_id, :tipo_de_obra, :codigo, :tipo_de_administracao_id,
		:classificacao_do_bem, :data_de_inicio, :data_prevista_de_termino, :descricao, :valor, :numero_do_crea
	].each do |atributo|
		it{ is_expected.to validate_presence_of atributo }
	end

	# it{ is_expected.to validate_uniqueness_of(:codigo).scoped_to(:orcamento_id).case_insensitive }
	# it{ is_expected.to validate_uniqueness_of(:contrato_id).case_insensitive }

	it{ is_expected.to validate_length_of( :tombo_do_terreno ).is_at_most(20) }
	it{ is_expected.to validate_length_of( :numero_do_crea ).is_at_most(25) }
	it{ is_expected.to validate_length_of( :tombo_da_construcao ).is_at_most(20) }
	it{ is_expected.to validate_length_of( :licenca_ambiental ).is_at_most(12) }
	it{ is_expected.to validate_length_of( :orgao_licenca ).is_at_most(80) }
	it{ is_expected.to validate_length_of( :cei ).is_at_most(12) }

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

	it { is_expected.to allow_value('01/01/2016').for(:data_da_licenca) }
	it { is_expected.to allow_value('').for(:data_da_licenca) }
	it { is_expected.to_not allow_value('00/').for(:data_da_licenca) }

	it { is_expected.to_not allow_value('').for(:data_de_inicio) }
	it { is_expected.to_not allow_value('00/').for(:data_de_inicio) }

	it { is_expected.to allow_value('01/01/2016').for(:data_prevista_de_termino) }
	it { is_expected.to_not allow_value('').for(:data_prevista_de_termino) }
	it { is_expected.to_not allow_value('00/').for(:data_prevista_de_termino) }

	describe "validate_presence_of :valor_estudos, :contrato_estudos_id" do
		context "valor_estudos presente." do
			contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
			subject{ FactoryBot.create(:obra_0001, codigo: '0001', contrato_estudos_id: contrato_2.id) }
			it { is_expected.to validate_presence_of :valor_estudos}
		end

		context "valor_estudos é maior que 0." do
			contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
			subject{ FactoryBot.create(:obra_0001, codigo: '0001', contrato_estudos_id: contrato_2.id) }
			it { is_expected.to validate_numericality_of( :valor_estudos).is_greater_than(0)}
		end

		context "contrato_estudos presente" do
			contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
			subject{
				obra = Contabilidade::Obra.create!(FactoryBot.attributes_for(:obra_0001, contrato_estudos_id: contrato_2.id, formulario_de_estudos: true, possui_estudos_projetos: true))
			}
			it { is_expected.to validate_presence_of :contrato_estudos_id}
		end
	end

	describe ".proximo_codigo_disponivel" do
		before(:each) do
			Contabilidade::Conta.find_by(codigo: "111100000") || FactoryBot.create( :conta_patrimonial_pai, :sem_validacao )#precisa para a classificacao de bem
		end
		context "quando não há obras cadastradas" do
			it "retorna 0001" do
				orcamento = Orcamento.find_or_create_by!( FactoryBot.attributes_for( :orcamento_2016 ) )
				expect(Contabilidade::Obra.proximo_codigo_disponivel(orcamento.id)).to eq '0001'
			end
		end

		context "quando há obras cadastradas" do
			it "retorna o próximo código" do
				obra = FactoryBot.create(:obra_0001, codigo: '0001')
				expect(Contabilidade::Obra.proximo_codigo_disponivel(obra.orcamento.id)). to eq '0002'
			end
		end

		context "quando há lacunas na sequência dos códigos" do
			it "retorna a primeira lacuna" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				obra_0003 = FactoryBot.create(:obra_0001, codigo: '0003')
				obra_0005 = FactoryBot.create(:obra_0001, codigo: '0005')
				expect(Contabilidade::Obra.proximo_codigo_disponivel(obra_0001.orcamento.id)).to eq '0002'
			end
		end

		context "saldo para medições" do
			it "não possui lançamentos" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')

				expect(obra_0001.saldo_para_medicoes).to eq obra_0001.valor
			end

			it "possui um lancamento de parte do valor da obra" do
				medicao_da_obra_0001 = FactoryBot.create(:medicao_da_obra_0001)

				expect(medicao_da_obra_0001.obra.saldo_para_medicoes).to eq (medicao_da_obra_0001.obra.valor - medicao_da_obra_0001.valor)
			end

			it "possui um lancamento de parte do valor total da obra" do
				medicao_da_obra_0001 = FactoryBot.create(:medicao_da_obra_0001, valor: 12345.67)

				expect(medicao_da_obra_0001.obra.saldo_para_medicoes).to eq 0
			end
		end

		context "total das medicoes" do
			it "não possui lançamentos" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')

				expect(obra_0001.total_das_medicoes).to eq 0
			end

			it "possui um lancamento de parte do valor da obra" do
				medicao_da_obra_0001 = FactoryBot.create(:medicao_da_obra_0001)

				expect(medicao_da_obra_0001.obra.total_das_medicoes).to eq medicao_da_obra_0001.valor
			end

			it "possui um lancamento de parte do valor total da obra" do
				medicao_da_obra_0001 = FactoryBot.create(:medicao_da_obra_0001, valor: 12345.67)

				expect(medicao_da_obra_0001.obra.total_das_medicoes).to eq medicao_da_obra_0001.obra.valor
			end
		end

		context "engenheiro responsável" do
			it "nao existe engenheiro responsavel" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')

				expect(obra_0001.engenheiro_responsavel).to eq nil
			end

			it "existe apenas um na lista de engenheiros responsaveis" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				engenheiro_01_da_obra = FactoryBot.create(:engenheiro_da_obra, obra_id: obra_0001.id)

				expect(obra_0001.engenheiro_responsavel.id).to eq engenheiro_01_da_obra.id
			end

			it "existe mais de um na lista de engenheiros responsaveis" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				engenheiro_01_da_obra = FactoryBot.create(:engenheiro_da_obra, obra_id: obra_0001.id)
				pessoa_2 = FactoryBot.create(:pessoa_juridica)
				engenheiro_02_da_obra = FactoryBot.create(:engenheiro_da_obra, obra_id: obra_0001.id, pessoa_id: pessoa_2.id, data_de_inicio: "20/10/2016" )

				expect(obra_0001.engenheiro_responsavel.id).to eq engenheiro_02_da_obra.id
			end
		end

		context "empresa responsável" do
			it "#adiciona_empresa_do_contrato_nas_empresas_da_obra" do
				#apos criar a obra, cria uma empresa responsavel a partir do contratado do contrato
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				expect(obra_0001.empresa_responsavel.pessoa).to eq obra_0001.contrato.contratado.pessoa
			end

			it "existe apenas um na lista de empresas responsaveis" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				empresa_01_da_obra = FactoryBot.create(:empresa_da_obra, obra_id: obra_0001.id)

				expect(obra_0001.empresa_responsavel.id).to eq empresa_01_da_obra.id
			end

			it "existe mais de um na lista de engenheiros responsaveis" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				empresa_01_da_obra = FactoryBot.create(:empresa_da_obra, obra_id: obra_0001.id)
				pessoa_2 = FactoryBot.create(:pessoa_juridica)
				empresa_02_da_obra = FactoryBot.create(:empresa_da_obra, obra_id: obra_0001.id, pessoa_id: pessoa_2.id )

				expect(obra_0001.empresa_responsavel.id).to eq empresa_02_da_obra.id
			end
		end

		context "situacao atual" do
			it "nao existe movimentação da obra" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')

				expect(obra_0001.situacao_atual.tipo_de_status_da_obra).to eq 'nao_iniciada'
			end

			it "existe apenas um na lista de situações" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				situacao_da_obra = FactoryBot.create(:situacao_em_andamento, obra_id: obra_0001.id)

				expect(obra_0001.situacao_atual.id).to eq situacao_da_obra.id
			end

			it "existe mais de um na lista de situações" do
				obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
				situacao_01_da_obra = FactoryBot.create(:situacao_em_andamento, obra_id: obra_0001.id)
				situacao_02_da_obra = FactoryBot.create(:situacao_paralisada, obra_id: obra_0001.id )

				expect(obra_0001.situacao_atual.id).to eq situacao_02_da_obra.id
			end
		end

		context "data prevista de termino nao pode ser anterior a data de inicio da obra" do
			it "data anterior a data de inicio da obra" do
				obra_0001 = FactoryBot.build(:obra_0001, codigo: '0001', data_de_inicio: Date.today, data_prevista_de_termino: Date.today - 1)
				obra_0001.validate

				expect(obra_0001.errors[:data_prevista_de_termino]).to include("deve ser maior que a data de início da obra")
			end

			it "data apos a data de inicio da obra" do
				obra_0001 = FactoryBot.build(:obra_0001, codigo: '0001', data_de_inicio: Date.today, data_prevista_de_termino: Date.today + 1)
				obra_0001.validate

				expect(obra_0001.errors[:data_prevista_de_termino]).not_to include("deve ser maior que a data de início da obra")
			end
		end
	end

	context "possui_medicoes?" do
		it "não possui" do
			obra = Contabilidade::Obra.new(valor: 10000)
			obra.save(validate: false)

			expect(obra.possui_medicoes?).to eq false
		end

		it "possui" do
			obra = Contabilidade::Obra.new(valor: 10000)
			obra.save(validate: false)
			medicao_da_obra = Contabilidade::MedicaoDaObra.new(valor: 10000, obra: obra)
			medicao_da_obra.save(validate: false)

			expect(obra.possui_medicoes?).to eq true
		end
	end

	context '#update_data_de_envio_pro_sim' do
		before do
			allow_any_instance_of(Contabilidade::Conta).to receive(:deve_ter_pai_cadastrado).and_return(true)
		end
		it 'atualiza a data de envio pro sim' do
			obra_0001 = FactoryBot.create(:obra_0001, codigo: '0001')
			obra_0001.update_data_de_envio_pro_sim("2016-10-30".to_date)
			expect(obra_0001.data_de_envio_pro_sim).to eq "2016-10-30".to_date
		end
	end

	describe do
		let(:contrato) { FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato }
		let(:valor_total_do_contrato) {
			contrato.itens_do_contrato.inject(0) { |total, item_do_contrato|
				FactoryBot.create :item_do_projeto_por_pessoa, final: true, preco: 9.99, item_do_lote: item_do_contrato.item_do_lote
				total + (9.99 * item_do_contrato.quantidade)
			}
		}
		describe "Funcionalidades de Estudos_e_Projetos" do
			context "Valor total dos Estudos e Projetos" do
				it "estudos e projetos com mesmo contrato da obra" do
					obra_0001 = FactoryBot.create( :obra_0001, codigo: '0001', contrato_id: contrato.id, contrato_estudos_id: contrato.id)
					obra_0001.reload

					expect(obra_0001.valor_total_estudos_e_projetos).to eq 0
				end

				it "estudos e projetos com contrato diferente da obra" do
					contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
					obra_0001 = FactoryBot.create( :obra_0001, codigo: '0001', contrato_id: contrato.id)
					obra_0001.contrato_estudos_id = contrato_2.id

					expect(obra_0001.valor_total_estudos_e_projetos).to eq 12345.67
				end

				it "valor de estudos igual ao do contrato estudos" do
					contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
					obra = Contabilidade::Obra.create!(FactoryBot.attributes_for(:obra_0001, contrato_id: contrato.id, mesmo_contrato: 'false', formulario_de_estudos: true, possui_estudos_projetos: true))
					obra.contrato_estudos_id = contrato_2.id

					expect(obra.buscar_valor_do_contrato_estudos_e_projetos).to eq obra.contrato_estudos.valor_total_do_contrato
				end

				it "valor de estudos diferente ao do contrato estudos" do
					contrato_2 = FactoryBot.create :licitacao_contrato, :com_lotes_do_contrato
					obra = Contabilidade::Obra.create!(FactoryBot.attributes_for(:obra_0001, contrato_id: contrato.id, mesmo_contrato: 'true', formulario_de_estudos: true, possui_estudos_projetos: true))

					expect(obra.contrato_id).to eq obra.contrato_estudos_id
				end
			end
		end
	end
end
