class Licitacao::PessoaDoProjeto < ApplicationRecord
	has_paper_trail

	attr_accessor :arquivo_cotacao
	attr_accessor :eh_proposta_final

	attr_default :credenciado, true
	attr_default :classificado, true

	belongs_to :projeto, class_name: 'Licitacao::Projeto', required: true
	belongs_to :pessoa, class_name: 'Base::Pessoa', required: true

	delegate :nome, to: :pessoa, prefix: :empresa

	has_many :contratados, inverse_of: :pessoa_do_projeto
	has_many :contratos, through: :contratados
	has_many :documentos_do_licitante, class_name:'Licitacao::DocumentoDoLicitante', dependent: :restrict_with_exception
	has_many :itens_do_projeto_por_pessoa, dependent: :destroy
	has_many :itens_do_lote, through: :itens_do_projeto_por_pessoa
	has_many :lances
	has_many :lotes, through: :itens_do_lote
	has_many :lotes_ganhos, class_name: "Licitacao::Lote", inverse_of: :ganhador, foreign_key: :ganhador_id
	has_many :pessoas_do_projeto_do_lote, dependent: :destroy, inverse_of: :pessoa_do_projeto

	accepts_nested_attributes_for :documentos_do_licitante, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :itens_do_projeto_por_pessoa, reject_if: :reject_itens_do_projeto_por_pessoa, allow_destroy: true

	validates_associated :itens_do_projeto_por_pessoa

	validates_presence_of :justificativa_descredenciado, unless: Proc.new{ self.credenciado? }
	validates_presence_of :justificativa_desclassificado, unless: Proc.new{ self.classificado? }
	# Validação retirada a pedido da consultoria de Contabilidade (Gleiciano e Lukas)
	# validates_presence_of :nome_do_responsavel, :tipo_de_responsavel, if: :itens_do_projeto_por_pessoa_preenchido?, on: :update
	validates_presence_of :cpf_do_responsavel, on: :update, if: Proc.new{ projeto && (projeto.chamamento_publico? || projeto.chamada_publica?) && itens_do_projeto_por_pessoa_preenchido?}

	validates_uniqueness_of :cpf_do_responsavel, scope: [:projeto_id], message: "já existe cotação para o CPF informado", if: Proc.new{ self.cpf_do_responsavel.present? }
	validates_uniqueness_of :pessoa_id, scope: :projeto_id

	validates_cpf :cpf_do_responsavel, allow_blank: true

	validate :preenchimento_dos_itens_corresponde_a_forma_de_agrupamento
	validate :valida_nome_do_arquivo_de_cotacao, :valida_mime_type_do_arquivo_de_cotacao

	# Validação retirada a pedido da consultoria de Contabilidade (Lukas)
	#validate :preenchimento_da_proposta_final_corresponde_ao_lance_final, unless: Proc.new {projeto && (projeto.dispensa_de_licitacao? || projeto.inexigibilidade_de_licitacao? || projeto.convite?) }

	enum tipo_de_responsavel: TIPOS_DE_RESPONSAVEIS
	before_validation :ler_arquivo_cotacao

	after_create :cria_pessoas_do_lote, if: Proc.new { projeto && projeto.lotes.any? }
	after_create :cria_ocorrencia_credenciamento

	alias_method :processo, :projeto

	scope :classificados, -> { where(classificado: true) }
	scope :desclassificados, -> { where(classificado: false) }
	scope :credenciados, -> { where(credenciado: true) }
	scope :descredenciados, -> { where(credenciado: false) }

	def valor_total
		itens_do_projeto_por_pessoa.iniciais.inject(0) {|total, item_do_projeto_por_pessoa|
			quantidade = item_do_projeto_por_pessoa.valido? ? item_do_projeto_por_pessoa.item_do_lote.item_do_pedido.quantidade_total_requisitada : 0
			total + (( item_do_projeto_por_pessoa.item_do_lote.item_do_pedido.por_preco? ? item_do_projeto_por_pessoa.preco.to_f : item_do_projeto_por_pessoa.item_do_lote.item_do_pedido.valor_total_previsto_por_desconto.to_f) * quantidade)
		}
	end

	def proposta_final
		itens_do_projeto_por_pessoa.finais.inject(0) {|total, item_do_projeto_por_pessoa|
			quantidade = item_do_projeto_por_pessoa.item_do_lote.item_do_pedido.quantidade_total_requisitada rescue 0
			total + (item_do_projeto_por_pessoa.preco.to_f * quantidade)
		}
	end

	def proposta_final_por_desconto
		total = 0
		lotes.distinct(:id).each do |lote|
			total += desconto_final_do_lote(lote)
		end
		return total.to_f.round(2)
	end

	def valor_total_do_lote lote
		regra_de_calculo = lote.try(:por_preco_e_valor_previsto?) ? "preco * periodicidade" : "preco * quantidade * periodicidade"
		itens_do_projeto_por_pessoa.where(item_do_lote: lote.itens_do_lote).validos.iniciais.
			joins(item_do_lote: [item_do_pedido: :itens_do_pedido_por_unidade_orcamentaria]).sum(regra_de_calculo)
	end

	def valor_total_final_do_lote lote
		itens_do_projeto_por_pessoa.where(item_do_lote: lote.itens_do_lote).finais.
			joins(item_do_lote: [item_do_pedido: :itens_do_pedido_por_unidade_orcamentaria]).sum("preco * quantidade * periodicidade")
	end

	def desconto_total_do_lote lote
		#Calculando desconto total levando em consideração valor previsto por item do lote
		soma_dos_descontos = 0
		soma_dos_valores_previstos = 0
		soma_das_porcentagem = 0
		busca_de_itens = itens_do_projeto_por_pessoa.where(item_do_lote: lote.itens_do_lote).validos.iniciais.joins(item_do_lote: [item_do_pedido: :itens_do_pedido_por_unidade_orcamentaria])

		busca_de_itens.each do |item|
			valor_previsto_por_item = item.item_do_lote.item_do_pedido.valor_total_previsto_por_desconto.to_f
			soma_das_porcentagem += valor_previsto_por_item * (item.preco.to_f/100)
			soma_dos_valores_previstos += valor_previsto_por_item
		end

		soma_dos_valores_previstos = (soma_dos_valores_previstos == 0) ? 1 : soma_dos_valores_previstos
		desconto_total = (soma_das_porcentagem * 100)/ soma_dos_valores_previstos
	end

	def desconto_final_do_lote lote
		#Calculando desconto total levando em consideração valor previsto por item do lote
		soma_dos_descontos = 0
		soma_dos_valores_previstos = 0
		soma_das_porcentagem = 0
		busca_de_itens = itens_do_projeto_por_pessoa.where(item_do_lote: lote.itens_do_lote).finais.joins(item_do_lote: [item_do_pedido: :itens_do_pedido_por_unidade_orcamentaria])

		busca_de_itens.each do |item|
			valor_previsto_por_item = item.item_do_lote.item_do_pedido.valor_total_previsto_por_desconto.to_f
			soma_das_porcentagem += valor_previsto_por_item * (item.preco.to_f/100)
			soma_dos_valores_previstos += valor_previsto_por_item
		end

		soma_dos_valores_previstos = (soma_dos_valores_previstos == 0) ? 1 : soma_dos_valores_previstos
		desconto_total = (soma_das_porcentagem * 100)/ soma_dos_valores_previstos
	end

	def inicia_proposta
		self.projeto.itens_do_lote.includes(item_do_pedido: [item: :unidade_de_medida]).where(anulado: false).each { |item_do_lote|
			if self.itens_do_projeto_por_pessoa.includes(:item_do_lote).where(item_do_lote_id: item_do_lote.id).empty? && self.itens_do_projeto_por_pessoa.select { |ipp| ipp.item_do_lote_id == item_do_lote.id }.empty?
				self.itens_do_projeto_por_pessoa.build(item_do_lote_id: item_do_lote.id, final: false)
			end
		}
	end

	def inicia_proposta_final
		unless projeto.por_item?
			lotes_ganhos.each { |lote|
				lote.itens_do_lote.each { |item_do_lote|
					if self.itens_do_projeto_por_pessoa.finais.where(item_do_lote_id: item_do_lote.id).empty? && self.itens_do_projeto_por_pessoa.select { |ipp| ipp.item_do_lote_id == item_do_lote.id && ipp.final? }.empty?
						proposta_inicial = itens_do_projeto_por_pessoa.iniciais.find_by(item_do_lote_id: item_do_lote.id)
						self.itens_do_projeto_por_pessoa.finais.build(item_do_lote_id: item_do_lote.id, marca: proposta_inicial.marca) if proposta_inicial.present?
					end
				}
			}
		end
	end

	def copia_proposta_inicial_para_final
		unless projeto.por_item?
			lotes_ganhos.each { |lote|
				lote.itens_do_lote.each { |item_do_lote|
					if self.itens_do_projeto_por_pessoa.finais.where(item_do_lote_id: item_do_lote.id).empty? && self.itens_do_projeto_por_pessoa.select { |ipp| ipp.item_do_lote_id == item_do_lote.id && ipp.final? }.empty?
						proposta_inicial = itens_do_projeto_por_pessoa.iniciais.find_by(item_do_lote_id: item_do_lote.id)
						self.itens_do_projeto_por_pessoa.finais.build(item_do_lote_id: item_do_lote.id, marca: proposta_inicial.marca, preco: proposta_inicial.preco) if proposta_inicial.present?
					end
				}
			}
		end
	end

	def descredenciar_e_desclassificar(justificativa)
		self.credenciado = false
		self.justificativa_descredenciado = justificativa
		self.save
		desclassificar("Desclassificado automaticamente por descredenciamento.")
	end

	def desclassificar(justificativa)
		self.classificado = false
		self.justificativa_desclassificado = justificativa
		#invalida todas as propostas da pessoa_do_projeto
		invalidar_propostas if self.save
	end

	def reclassificar
		self.classificado = true
		self.justificativa_desclassificado = ''
		#revalida todas as propostas da pessoa_do_projeto
		validar_propostas if self.save
	end

	def invalidar_propostas
		self.itens_do_projeto_por_pessoa.update_all( valido: false )
	end

	def validar_propostas
		self.itens_do_projeto_por_pessoa.update_all( valido: true )
	end

	def anular_lote(lote_id)
		if self.itens_do_projeto_por_pessoa.joins(:item_do_lote).merge(Licitacao::ItemDoLote.where(lote_id: lote_id)).update_all( valido: false)
			#anula o lote se todos os itens do lote forem anulados
			self.lotes.find(lote_id).update(anulado: true) if self.lotes.find(lote_id).itens_do_projeto_por_pessoa.all? {|idppp| !idppp.valido? }
			#desclassifica o licitante se todos as propostas dele forem anuladas
			desclassificar("Desclassificado automaticamente por anular todas as propostas.") if self.itens_do_projeto_por_pessoa.all? {|idppp| !idppp.valido? }
		end
	end

	def reverter_anulacao_lote(lote_id)
		if self.itens_do_projeto_por_pessoa.joins(:item_do_lote).merge(Licitacao::ItemDoLote.where(lote_id: lote_id)).update_all( valido: true)
			self.lotes.find(lote_id).update(anulado: false)
			reclassificar
		end
	end

	def deleta_pessoa_do_projeto
		ActiveRecord::Base.transaction do
			itens_do_projeto_por_pessoa.destroy_all
			pessoas_do_projeto_do_lote.destroy_all
			self.delete
		end
	end

	def itens_do_projeto_por_pessoa_validos?(lote_id)
		self.itens_do_projeto_por_pessoa.joins(:item_do_lote).merge(Licitacao::ItemDoLote.where(lote_id: lote_id)).all? {|idppp| idppp.valido? }
	end

	def ganhou_algum_lote?
		lotes_ganhos.any?
	end

	def lotes_ganhos_ativos
		lotes_ganhos.ativo
	end

	def proposta_preenchida?
		lotes.any?
	end

	def proposta_final_prenchida?
		itens_dos_lotes_ganhos = 0

		lotes_ganhos.each do |lote|
			itens_dos_lotes_ganhos += itens_do_projeto_por_pessoa.finais.where(item_do_lote_id: [lote.itens_do_lote.ids]).count
		end
		itens_do_projeto_por_pessoa.finais.count > itens_dos_lotes_ganhos
	end

	def possui_lances_de_lotes_ativos?
		lotes.ativos.all? {|lote|
			return true if lote.lances.any?
		}
		return false
	end

	def lote_preenchido? lote
		itens_preenchidos = itens_do_projeto_por_pessoa.select { |ipp| ipp.item_do_lote.lote.id == lote.id }
		(lote.itens_do_lote.ativos.to_a - itens_preenchidos.map(&:item_do_lote)) == []
	end

	def participando_do_lote? lote
		itens_do_projeto_por_pessoa.where(item_do_lote_id: [lote.itens_do_lote.ids]).count > 0
	end

	def menor_proposta?
		if self.projeto.global?
			menor_valor = self.projeto.pessoas_do_projeto.classificados.map {|pessoa_do_projeto| pessoa_do_projeto.valor_total }.reject{ |valor_total| valor_total == 0}.min
			self.valor_total == menor_valor
		end
	end

	def pessoa_do_lote_habilitado? lote
		self.pessoas_do_projeto_do_lote.where(pessoa_do_projeto_id: self.id, lote_id: lote.id, habilitado: true).count > 0
	end

	# TCM
	def valida_pessoa_juridica
		raise "O Fornecedor possui CNPJ mas não é Pessoa Jurídica: " << "#{pessoa.nome}" if !pessoa.pessoa_juridica? && !pessoa.cnpj.blank?
	end

	def valida_cep_pessoa
		raise "O CEP do Fornecedor deve ser informado: " << "#{pessoa.nome}" if pessoa.cep.nil?
	end

	def valida_email_pessoa
		raise "O E-mail do Fornecedor(OSC) deve ser informado: " << "#{pessoa.nome}" if pessoa.email.blank?
	end

	def cpf_responsavel_existente? pessoa_do_projeto_cpf
		pessoa_do_projeto_cpf_formatado = pessoa_do_projeto_cpf.gsub(/[.-]/,'')
		if !pessoa_do_projeto_cpf_formatado.blank? && projeto.pessoas_do_projeto.where.not(id: self.id).where(cpf_do_responsavel: pessoa_do_projeto_cpf_formatado ).any?
			errors.add(:cpf_do_responsavel, "Não é possível adicionar responsáveis com mesmo cpf")
			return true
		end
		return false
	end

	private

	def cria_pessoas_do_lote
		projeto.lotes.each do |lote|
			pessoas_do_projeto_do_lote.find_or_create_by!(lote_id: lote.id)
		end
	end

	def cria_ocorrencia_credenciamento
		unless projeto.try(:ocorrencias).try(:credenciamento).try(:any?)
			projeto.ocorrencias.create(data_da_ocorrencia: Date.today, horario_da_ocorrencia: Time.now.strftime("%H:%M"), tipo: "credenciamento", motivo: "Credenciamento") if projeto.present?
		end
	end

	def reject_itens_do_projeto_por_pessoa(ipp)
		item_do_lote = Licitacao::ItemDoLote.find(ipp['item_do_lote_id'].to_i)

		if item_do_lote.item_do_pedido.por_desconto?
			ipp['marca'].blank? && ipp['preco'].blank?
		else
			ipp['preco'].blank? || ipp['preco'] == "0" || ipp['preco'] == 0
		end
	end

	def valida_nome_do_arquivo_de_cotacao
		if arquivo_cotacao.present?
			errors.add(:arquivo_cotacao, "nome do arquivo deve corresponder ao CNPJ ou CPF do licitante sem pontos e traço") unless self.arquivo_cotacao.original_filename.include?(self.pessoa.cpf_ou_cnpj_sem_pontos)
		end
	end

	def valida_mime_type_do_arquivo_de_cotacao
		if arquivo_cotacao.present?
			errors.add(:arquivo_cotacao, "arquivo não corresponde ao formato esperado") unless self.arquivo_cotacao.content_type.include?("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
		end
	end

	def ler_arquivo_cotacao
		if self.arquivo_cotacao.present? && self.arquivo_cotacao.original_filename.include?(self.pessoa.cpf_ou_cnpj_sem_pontos) && self.arquivo_cotacao.content_type.include?("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
			xlsx = SimpleXlsxReader.open(self.arquivo_cotacao.path)
			xlsx.sheets[0].rows[1..-1].each do |row|
				item_do_lote = self.projeto.itens_do_lote.find_by(identificador: row[0])
				if item_do_lote.present?
					item_do_projeto_por_pessoa = self.itens_do_projeto_por_pessoa.find_all {|x| x.item_do_lote_id == item_do_lote.id }
					if item_do_projeto_por_pessoa.size > 0
						item_do_projeto_por_pessoa.first.marca = row[1]
						item_do_projeto_por_pessoa.first.preco = row[2]
					end
				end
			end
		end
	end

	def preenchimento_dos_itens_corresponde_a_forma_de_agrupamento
		msg = nil
		if projeto && projeto.por_lote?
			itens_preenchidos = itens_do_projeto_por_pessoa.select { |ipp| ipp.preco.present? }
			lotes_com_valor = itens_preenchidos.map { |ipp| ipp.item_do_lote.lote }.uniq
			lotes_com_valor.each do |lote|
				msg = "Todos os elementos do lote devem ser preenchidos nessa forma de agrupamento" unless lote_preenchido?(lote)
			end
		elsif projeto && projeto.global?
			itens_preenchidos = itens_do_projeto_por_pessoa.map { |ipp| ipp.item_do_lote if ipp.marca.present? && ipp.preco.present? }.compact
			itens_do_projeto = projeto.itens_do_lote.ativos.to_a
			msg = "Todos os elementos devem ser preenchidos nessa forma de agrupamento" if itens_preenchidos.any? && (itens_do_projeto - itens_preenchidos).any?
		end

		errors.add(:base, msg) if msg
		return false
	end

	def preenchimento_da_proposta_final_corresponde_ao_lance_final
		propostas_finais = itens_do_projeto_por_pessoa.select { |item_do_projeto_por_pessoa| item_do_projeto_por_pessoa.final? }
		if propostas_finais.any?
			propostas_finais_por_lote = propostas_finais.group_by { |item_do_projeto_por_pessoa| item_do_projeto_por_pessoa.item_do_lote.lote }
			proposta_final_corresponde_ao_lance_final = propostas_finais_por_lote.all? { |lote, itens_do_projeto_por_pessoa|
				pessoa_do_projeto_do_lote = pessoas_do_projeto_do_lote.find_by(lote_id: lote.id)
				valor_final = (lote.processo.tomada_de_precos? || lote.processo.carona? || lote.processo.convite? || lote.processo.contratacao_consultoria_individual? || lote.processo.parceria_osc?) ? pessoa_do_projeto_do_lote.pessoa_do_projeto.valor_total_do_lote(lote) : pessoa_do_projeto_do_lote.lance_final
				valor_final.to_f.round(2) == itens_do_projeto_por_pessoa.inject(0) { |soma_dos_itens, item| soma_dos_itens + item.valor_final }.to_f.round(2)
			}
			unless proposta_final_corresponde_ao_lance_final
				errors.add(:itens_do_projeto_por_pessoa, "As propostas finais não batem com o lance vencedor")
			end
		end
	end

	def itens_do_projeto_por_pessoa_preenchido?
		self.itens_do_projeto_por_pessoa.any?
	end
end
