class Licitacao::Lance < ApplicationRecord
	has_paper_trail

	attr_default :desistir, false

	attr_accessor :lance_final

	belongs_to :rodada
	belongs_to :pessoa_do_projeto

	delegate :projeto, to: :pessoa_do_projeto

	before_validation :preenche_valor_com_valor_anterior, if: :lance_final

	scope :nao_concluidos, -> { where("(valor is null or valor <= 0) and desistir is false") }
	scope :decrescente, -> { order("VALOR DESC") }

	validates_presence_of :rodada_id, :pessoa_do_projeto_id
	validates_presence_of :valor, unless: Proc.new { self.desistir? }
	validates_absence_of :valor, if: Proc.new { self.desistir? }

	validates :valor, casas_decimais: 4, unless: Proc.new { (rodada && rodada.lote.processo.por_item?) || self.desistir? }
	validates_numericality_of :valor, greater_than: 0, unless: Proc.new { self.desistir? }

	validate :deve_ser_menor_que_o_menor_valor_da_rodada_anterior, unless: Proc.new { (rodada && rodada.lote.lote_por_desconto?) || self.desistir? || lance_final }
	validate :deve_ser_maior_que_o_maior_valor_da_rodada_anterior, if: Proc.new { (rodada && rodada.lote.lote_por_desconto?) && !self.desistir? && !lance_final}

	def valor_anterior
		if rodada.numero == 1
			if rodada.lote.processo.por_item?
				pessoa_do_projeto.itens_do_projeto_por_pessoa.where(item_do_lote: rodada.lote.itens_do_lote).iniciais.sum(:preco)
			elsif rodada.lote.lote_por_desconto?
				pessoa_do_projeto.desconto_total_do_lote(rodada.lote)
			else
				pessoa_do_projeto.itens_do_projeto_por_pessoa.where(item_do_lote: rodada.lote.itens_do_lote).inject(0) { |total, item_do_projeto_por_pessoa|
					total + item_do_projeto_por_pessoa.total
				}
			end
		else
			self.class.joins(rodada: :lances).find_by( licitacao_rodadas: {numero: rodada.numero - 1, lote_id: self.rodada.lote_id}, licitacao_lances: { pessoa_do_projeto_id: pessoa_do_projeto.id } ).valor.to_f
		end
	end

	def menor_valor_da_rodada_anterior
		if rodada.numero == 1
			if rodada.lote.processo.por_item?
				preco_por_pessoa_do_projeto = Licitacao::ItemDoProjetoPorPessoa.where(item_do_lote: rodada.lote.itens_do_lote).group(:pessoa_do_projeto_id).sum(:preco)
				preco_por_pessoa_do_projeto.to_a.map {|_, preco| preco }.min
			else
				preco_por_pessoa_do_projeto = rodada.lote.pessoas_do_projeto_elegiveis_para_lances_verbais.map{ |pessoa_do_projeto|
					pessoa_do_projeto.valor_total_do_lote(rodada.lote)
				}
				preco_por_pessoa_do_projeto.min
			end
		else
			self.rodada.rodada_anterior.menor_lance
		end
	end

	def deleta_lances_das_rodadas_iniciais
		lote = self.rodada.lote
		rodada_um = lote.rodadas.find_by_numero(1)
		lance_rodada_um =  rodada_um.lances.find_by_pessoa_do_projeto_id(self.pessoa_do_projeto_id)

		self.destroy
		lance_rodada_um.destroy
	end

	def anula_itens_lance
		lote = self.rodada.lote
		self.pessoa_do_projeto.itens_do_projeto_por_pessoa.joins(:item_do_lote).merge(Licitacao::ItemDoLote.where(lote_id: lote.id)).update_all( valido: false)
		lote.update(anulado: true) if lote.itens_do_projeto_por_pessoa.all? {|idppp| !idppp.valido? }
	end

	def maior_valor_da_rodada_anterior
		if rodada.numero == 1
			if rodada.lote.processo.por_item?
				preco_por_pessoa_do_projeto = Licitacao::ItemDoProjetoPorPessoa.where(item_do_lote: rodada.lote.itens_do_lote).group(:pessoa_do_projeto_id).sum(:preco)
				preco_por_pessoa_do_projeto.to_a.map {|_, preco| preco }.max
			else
				preco_por_pessoa_do_projeto = rodada.lote.pessoas_do_projeto_elegiveis_para_lances_verbais.map{ |pessoa_do_projeto|
					pessoa_do_projeto.desconto_total_do_lote(rodada.lote)
				}
				preco_por_pessoa_do_projeto.max
			end
		else
			self.rodada.rodada_anterior.maior_lance
		end
	end

	private

	def deve_ser_menor_que_o_menor_valor_da_rodada_anterior
		if rodada.present?
			if rodada.numero.to_i == 1
				errors.add(
					:valor, "deve ser menor que o menor valor da oferta inicial"
				) unless valor && menor_valor_da_rodada_anterior && valor < menor_valor_da_rodada_anterior
			elsif rodada.numero.to_i > 1
				errors.add(
					:valor, "deve ser menor que o menor lance da rodada anterior"
				) unless valor && menor_valor_da_rodada_anterior && valor < menor_valor_da_rodada_anterior
			end
		end
	end

	def deve_ser_maior_que_o_maior_valor_da_rodada_anterior
		if rodada.present?
			if rodada.numero.to_i == 1
				errors.add(
					:valor, "deve ser maior que o maior valor da oferta inicial"
				) if valor.nil? || maior_valor_da_rodada_anterior.nil? || (valor <= maior_valor_da_rodada_anterior)
			elsif rodada.numero.to_i > 1
				errors.add(
					:valor, "deve ser maior que o maior lance da rodada anterior"
				) unless valor && maior_valor_da_rodada_anterior && (valor > maior_valor_da_rodada_anterior)
			end
		end
	end

	def preenche_valor_com_valor_anterior
		self.valor ||= valor_anterior
	end
end
