require 'rails_helper'
require 'licitacao_helper'

RSpec.configure do |c|
  c.include LicitacaoHelper
end


RSpec.describe Licitacao::ProcessosController, type: :controller do
	sign_in_admin
	cria_configuracao_default
	set_licitacao_na_sessao

	# Isso deve retornar o mínimo de atributos obrigatórios para criar um
	# Licitacao::Processo válido.

	let(:atributos_validos) {
		FactoryBot.attributes_for( :licitacao_processo, status: "em_sessao" )
	}

	let(:atributos_invalidos) {
		{ pedido_id: nil }
	}

	let(:processo) {
		FactoryBot.create :licitacao_processo, :por_item, status: "em_sessao"
	}

	let(:processo_com_ganhadores_em_todos_os_lotes) {
		processo.lotes.last.delete
		processo.reload
		processo.lotes.each_with_index do |lote, index|
			lote.ganhador_id = processo.pessoas_do_projeto[index].id
			lote.status = 'ativo'
			lote.update!(lances_abertos: false)
			lote.save
		end
		processo.reload
	}

	describe "GET #index" do
		it "atribui a lista de processos à @processos" do
			processo = Licitacao::Processo.create! atributos_validos
			get :index
			expect(assigns(:processos)).to eq([processo])
		end
	end

	describe "GET #show" do
		it "atribui o processo requisitado à @processo" do
			processo = Licitacao::Processo.create! atributos_validos
			get :show, params: {id: processo.to_param}
			expect(assigns(:processo)).to eq(processo)
		end
	end

	describe "GET #edit" do
		it "atribui o processo requisitado à @processo" do
			processo = Licitacao::Processo.create! atributos_validos
			get :edit, params: {id: processo.to_param}
			expect(assigns(:processo)).to eq(processo)
		end
	end

  describe "PATCH #nao_enviar_para_sim" do
		it "for processo de dispensa" do
      processo = FactoryBot.create :licitacao_processo, status: :aguardando_homologacao, modalidade_do_processo: :dispensa_de_licitacao, modalidade_de_licitacao: :dispensa_ou_inexigibilidade, forma_de_agrupamento: :por_item, tipo_de_totalizacao: :menor_valor, envia_pro_sim: true
      processo.update_column(:envia_pro_sim, false)
      expect redirect_to(processo)
		end
	end

  describe "PATCH #enviar_para_sim" do
		it "for processo de dispensa" do
      processo = FactoryBot.create :licitacao_processo, status: :aguardando_homologacao, modalidade_do_processo: :dispensa_de_licitacao, modalidade_de_licitacao: :dispensa_ou_inexigibilidade, forma_de_agrupamento: :por_item, tipo_de_totalizacao: :menor_valor, envia_pro_sim: false
      processo.update_column(:envia_pro_sim, true)
      expect redirect_to(processo)
		end
	end

	describe "PUT #update" do
		context "com parâmetros válidos" do
			let(:novos_atributos) {
				{numero_do_processo: '123456'}
			}

			it "atualiza o(a) processo requisitado(a)" do
				processo = Licitacao::Processo.create! atributos_validos
				post :update, params: {id: processo.to_param, licitacao_processo: novos_atributos}
				processo.reload
				expect( processo.numero_do_processo ).to eq '123456'
			end

			it "atribui o(a) processo requisitado(a) à @processo" do
				processo = Licitacao::Processo.create! atributos_validos
				post :update, params: {id: processo.to_param, licitacao_processo: atributos_validos}
				expect(assigns(:processo)).to eq(processo)
			end

			it "redireciona para o(a) processo" do
				processo = Licitacao::Processo.create! atributos_validos
				post :update, params: {id: processo.to_param, licitacao_processo: atributos_validos}
				expect(response).to redirect_to(processo)
			end
		end

		context "com parâmetros inválidos" do
			it "atribui o(a) processo à @processo" do
				processo = Licitacao::Processo.create! atributos_validos
				post :update, params: {id: processo.to_param, licitacao_processo: atributos_invalidos}
				expect(assigns(:processo)).to eq(processo)
			end
		end
	end

	describe "PATCH #homologar" do
		context 'quando o status é válido (aguardando_homologacao)' do
			it 'atribui o status homologado e redireciona com sucesso' do
				processo = FactoryBot.create :licitacao_processo, status: :aguardando_homologacao
				FactoryBot.create( :licitacao_documento_do_processo, :parecer, projeto_id: processo.id, status_parecer: 'concluido' )
				patch :homologar, { id: processo.to_param }
				expect(response).to redirect_to(processo)
				expect(flash[:notice]).to include 'Processo homologado com sucesso.'
			end
		end

		context 'quando o status é inválido (pos_sessao)' do
			before(:each) do
				@processo = FactoryBot.create :licitacao_processo, status: :em_sessao
			end
			it 'retorna para o show de processo com erro' do
				patch :homologar, {id: @processo.to_param}
				expect(response).to redirect_to(@processo)
				expect(flash[:alert]).to include "Não é possível passar da fase atual para a requisitada."
			end

			it 'não muda: de status' do
				expect {
					patch :homologar, {id: @processo.to_param}
				}.to_not change{Licitacao::Processo.find(@processo.id).status}
			end
		end
	end

	describe "PATCH #fracassar_processo" do
		context 'quando o status é em_sessao' do
			it 'atribui o status fracassar_processo e redireciona para processo com sucesso' do
				processo = Licitacao::Processo.create! atributos_validos
				publicacao = FactoryBot.create :licitacao_publicacao, projeto_id: processo.id
				processo.update_attributes(data_da_sessao: (publicacao.data_da_publicacao + 20) )
				processo.lotes.each { |lote| lote.fracassado! }
				patch :fracassar_processo, {id: processo.to_param}
				expect(response).to redirect_to(processo)
				expect(flash[:notice]).to include 'O processo foi marcado como fracassado.'

				expect(processo.reload.fracassado?).to be_truthy
			end
		end
	end

	describe "PATCH #concluir_sessao" do
		context 'quando o status é válido (em_sessao)' do
      before(:each) do
        allow_any_instance_of(Licitacao::PessoaDoProjeto).to receive( :preenchimento_da_proposta_final_corresponde_ao_lance_final ).and_return(true)
      end
			it 'atribui o status pos_sessao e redireciona para processo com sucesso' do
				processo = processo_com_ganhadores_em_todos_os_lotes
				publicacao = FactoryBot.create :licitacao_publicacao, projeto_id: processo.id
				processo.update_column(:data_da_sessao, (publicacao.data_da_publicacao + 20) )

				processo.itens_do_lote.each do |item_do_lote|
					FactoryBot.create :item_do_projeto_por_pessoa,
						pessoa_do_projeto: processo.lotes.first.ganhador, item_do_lote_id: item_do_lote.id, preco: 19.98, final: true
				end
				patch :concluir_sessao, {id: processo.to_param}
        expect(response).to redirect_to(processo)
				expect(flash[:notice]).to include 'Sessão concluída.'

				expect(processo.reload.pos_sessao?).to be_truthy
			end
		end

		context 'quando o status é inválido (cancelado)' do
			it 'não muda status pro processo' do
				processo = FactoryBot.create :licitacao_processo, status: :cancelado
				expect{patch :concluir_sessao, {id: processo.to_param}}.to_not change{Licitacao::Processo.find(processo.id).status}
			end
		end
	end

	describe "GET #editar_licitantes" do
		context 'quando processo está na fase "em_sessao"' do
			it "atribui o processo requisitado à @processo" do
				processo = FactoryBot.create :licitacao_processo, status: :em_sessao
				get :editar_licitantes, {id: processo.to_param}
				expect(assigns(:processo)).to eq(processo)
			end
		end

		[:cancelado, :aberto, :homologado, :aguardando_publicacao, :em_recurso, :pos_sessao ].each do |status|
			context 'quando processo está na fase "#{status}"' do
				it "retorna mensagem de erro" do
					processo = FactoryBot.create :licitacao_processo, status: status
					get :editar_licitantes, {id: processo.to_param}
					expect(response).to redirect_to(processo)
					expect(flash[:alert]).to eq("Essa ação não é permitida nessa etapa")
				end
			end
		end

		context 'quando já existem lances abertos e modalidade é pregão' do
			it 'não é possível adicionar ou remover licitantes' do
				processo = FactoryBot.create :licitacao_processo, modalidade_de_licitacao: :pregao_presencial, status: :em_sessao
				pessoa_do_projeto = FactoryBot.create(:licitacao_pessoa_do_projeto, projeto_id: processo.id)
				processo.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

				lote = processo.lotes.first
				lote.update_column(:lances_abertos, true)

				lote.rodadas.create!
				get :editar_licitantes, {id: processo.to_param}
				expect(response).to redirect_to(processo)
				expect(flash[:alert]).to eq("Não é possível adicionar ou remover licitantes, pois já existem lances abertos")
			end
		end

		[:tomada_de_precos, :carona, :concorrencia_publica, :convite].each do |modalidade|
			context 'quando já existem notas técnicas e modalidade é "#{modalidade}"' do
				it 'não é possível adicionar ou remover licitantes' do
					allow_any_instance_of(Licitacao::Projeto).to receive(:valida_valor_orcamentario).and_return(true)
					processo = FactoryBot.create :licitacao_processo, :melhor_tecnica, status: "em_sessao", modalidade_de_licitacao: modalidade
					processo.reload
					lote = processo.lotes.first
					pessoa_do_projeto = processo.pessoas_do_projeto.first
					lote.pessoas_do_projeto_do_lote.create!(pessoa_do_projeto_id: pessoa_do_projeto.id, lote_id: lote.id, nota_tecnica: 10)
					get :editar_licitantes, {id: processo.to_param}
					expect(response).to redirect_to(processo)
					expect(flash[:alert]).to eq("Não é possível adicionar ou remover licitantes, pois já existem notas técnicas preenchidas")
				end
			end
		end
	end

	describe '#atualizar_licitantes' do
		context "com parâmetros válidos" do
      before(:each) do
        allow_any_instance_of(Licitacao::PessoaDoProjeto).to receive( :preenchimento_da_proposta_final_corresponde_ao_lance_final ).and_return(true)
      end
			let(:atributos_pessoas_do_projeto) {
				{
						pessoas_do_projeto_attributes: {
								'0': { pessoa_id: Base::Pessoa.find_or_create_by(FactoryBot.attributes_for :pessoa_juridica, nome: "teste").id }
						}
				}
			}
			it 'atualiza o processo com os licitantes' do
				patch :atualizar_licitantes, {id: processo.to_param, licitacao_processo: atributos_pessoas_do_projeto}
				processo.reload
				expect(processo.pessoas_do_projeto.second.pessoa.nome).to eq "teste"
			end

			it 'remove um licitante e atualiza o processo' do
				pessoa_do_projeto = processo.reload.pessoas_do_projeto.first
				hash_exclusao = {
					pessoas_do_projeto_attributes: {
						'0': {id:  pessoa_do_projeto.id,  :_destroy => "1"},
					}
				}
				expect {
					patch :atualizar_licitantes, {id: processo.to_param, licitacao_processo: hash_exclusao }
				}.to change(processo.pessoas_do_projeto, :count).from(1).to(0)
			end
		end

		context "com parâmetros inválidos" do
			let(:pessoas_invalidas) {
				id = Base::Pessoa.find_or_create_by(FactoryBot.attributes_for :pessoa_juridica, nome: "teste").id
				{
						pessoas_do_projeto_attributes: {
								'0': { pessoa_id: id },
								'1': { pessoa_id: id }
						}
				}
			}
			it 're-renderiza o template :editar_licitantes' do
				patch :atualizar_licitantes, {id: processo.to_param, licitacao_processo: pessoas_invalidas}
				expect(response).to render_template("editar_licitantes")
			end
		end
	end

	describe "GET #editar_dados_do_sim" do
		it "atribui o processo requisitado à @processo" do
			processo = FactoryBot.create :licitacao_processo, status: :em_sessao
			get :editar_dados_do_sim, {id: processo.to_param}
			expect(assigns(:processo)).to eq(processo)
		end
	end

	describe "PATCH #atualizar_dados_do_sim" do
		context "com parâmetros válidos" do
			let(:data_valida) {
				{ envia_pro_sim: true }
				{ data_de_envio_pro_sim: Date.today }
			}

			it "atualiza o processo requisitado e redireciona pro @processo" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :atualizar_dados_do_sim, { id: processo.to_param, licitacao_processo: data_valida }
				processo.reload
				expect(processo.data_de_envio_pro_sim).to eq Date.today
			end
		end

		context "com parâmetros inválidos" do
			let(:data_invalida) {
				{ envia_pro_sim: true }
				{ data_de_envio_pro_sim: nil }
			}

			it "não atualiza o processo e re-renderiza o template :editar_dados_do_sim" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :atualizar_dados_do_sim, {id: processo.to_param, licitacao_processo: data_invalida}
				expect(response).to render_template("editar_dados_do_sim")
			end
		end
	end

	describe "GET #fornecedores" do
		render_views
		it "lista fornecedores do processo" do
			processo = FactoryBot.create :licitacao_processo, status: :homologado
			_pessoa_do_projeto = FactoryBot.create :licitacao_pessoa_do_projeto, projeto: processo
			get :fornecedores, { id: processo.id, format: :json }
			processo.reload
			retorno = [{"id" => processo.pessoas_do_projeto.first.id, "cpf_ou_cnpj_e_nome" => processo.pessoas_do_projeto.first.pessoa.cpf_ou_cnpj_e_nome}]
			expect(JSON.parse(response.body)).to eq retorno
		end
	end

	describe "GET #unidades_orcamentarias" do
		render_views
		it "lista unidades orçamentárias do processo" do
			processo = FactoryBot.create :licitacao_processo, status: :homologado
			get :unidades_orcamentarias, { id: processo.id, format: :json }
			processo.reload
			retorno = processo.unidades_orcamentarias
			expect(JSON.parse(response.body)).to eq JSON.parse(retorno.to_json)
		end
	end

	describe 'PATH #desertar' do
		let(:processo) {
			FactoryBot.create :licitacao_processo, :por_lote, status: "em_sessao", modalidade_de_licitacao: :pregao_presencial
		}
    before(:each) do
      allow_any_instance_of(Licitacao::PessoaDoProjeto).to receive( :preenchimento_da_proposta_final_corresponde_ao_lance_final ).and_return(true)
    end
		describe 'se todos os lotes estiverem desertados' do
			it "deserta o processo e redireciona para o @processo com mensagem de sucesso" do
				processo.lotes.each { |lote| lote.deserto! }
				patch :desertar, {id: processo.id}
				expect(response).to redirect_to(licitacao_processo_path(processo))
				expect(flash[:notice]).to include "O processo foi desertado"
			end
		end

		describe 'se todos os lotes não estiverem desertados' do
			it "não deserta o processo e redireciona para o @processo com mensagem de erro" do
				primeiro_lote = processo.lotes.first
				primeiro_lote.deserto!
				patch :desertar, {id: processo.id}
				expect(response).to redirect_to(licitacao_processo_path(processo))
				expect(flash[:alert]).to include "Não é possível passar da fase atual para a requisitada."
			end
		end
	end

  describe "PATCH #cancelar" do
		context "com parâmetros válidos" do
			let(:novos_atributos) {
				{motivo_do_cancelamento: "motivo convincente"}
			}

			it "atualiza o(a) pedido requisitado(a)" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :cancelar, {id: processo.to_param, licitacao_processo: novos_atributos}
				processo.reload
				expect(processo.motivo_do_cancelamento).to eq "motivo convincente"
			end

			it "muda status do processo para 'cancelado'" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :cancelar, {id: processo.to_param, licitacao_processo: novos_atributos}
				processo.reload
				expect(processo.cancelado?).to be_truthy
			end

			it "atribui o(a) processo requisitado(a) à @processo" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :cancelar, {id: processo.to_param, licitacao_processo: novos_atributos}
				expect(assigns(:processo)).to eq(processo)
			end

			it "redireciona para o(a) processo" do
				processo = Licitacao::Processo.create! atributos_validos
				patch :cancelar, {id: processo.to_param, licitacao_processo: novos_atributos}
				expect(response).to redirect_to(processo)
			end
		end
	end

	describe "GET #busca_licitantes" do
		context 'quando processo está em sessão' do
			it 'atribui pessoas à @pessoas' do
				pessoa = FactoryBot.create(:pessoa_juridica)
				get :busca_licitantes, {id: processo.to_param, q: {nome_cont: pessoa.nome}}
				expect(assigns(:pessoas).first).to eq(pessoa)
			end
		end
	end

	describe "PATCH #adiciona_licitantes" do
		context 'quando é passado pessoas por parâmetros' do
			it 'adiciona pessoas à @processo' do
				pessoa = FactoryBot.create(:pessoa_juridica)
				get :adiciona_licitantes, { id: processo.to_param, pessoas: [pessoa.id] }
				expect(response).to render_template("editar_licitantes")
				expect(flash[:notice]).to include "1 Licitante adicionado com sucesso"
			end
		end

		context 'quando não é passado pessoas por parâmetros' do
			it 'não adiciona pessoas à @processo' do
				processo.pessoas_do_projeto.destroy_all
				get :adiciona_licitantes, { id: processo.to_param, pessoa: [] }
				expect(processo.reload.pessoas_do_projeto.count).to be == 0
			end

			it 'redireciona para a tela anterior' do
				get :adiciona_licitantes, { id: processo.to_param, pessoa: [] }
				expect(response).to redirect_to(busca_licitantes_licitacao_processo_path(processo))
			end
		end
	end
end
