class Licitacao::ItemDoPedido < ApplicationRecord
	has_paper_trail
	include TradutorConcern

	attr_accessor :lote_do_pedido
	attr_accessor :sequencia_do_lote
	attr_default :valido, true
	attr_default :tipo, :por_preco

	belongs_to :pedido, inverse_of: :itens_do_pedido
	belongs_to :item, class_name: 'Base::Item'

	has_many :itens_do_pedido_por_unidade_orcamentaria, inverse_of: :item_do_pedido, dependent: :destroy
	has_many :itens_do_pedido_por_pessoa, class_name: 'Licitacao::ItemDoPedidoPorPessoa', inverse_of: :item_do_pedido, dependent: :destroy
	has_one :item_do_lote
	has_one :item_do_lote_do_pedido, class_name: 'Licitacao::ItemDoLoteDoPedido'
	has_many :item_do_contrato, class_name: 'Licitacao::ItemDoContrato'

	accepts_nested_attributes_for :itens_do_pedido_por_unidade_orcamentaria, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :itens_do_pedido_por_pessoa, reject_if: :all_blank, allow_destroy: true

	validates_associated :itens_do_pedido_por_unidade_orcamentaria
	validates_associated :itens_do_pedido_por_pessoa

	validates_uniqueness_of :item_id, scope: [:pedido_id, :valido], if: Proc.new{ self.persisted? && self.valido? }
	validates_presence_of :motivo, unless: Proc.new{ self.valido? }
	validates_presence_of :tipo
	validates_presence_of :item_id

	validate :valida_se_item_simplificado_possui_preco_estimativo
	validate :valida_nao_pode_ser_por_desconto

	delegate :descricao, to: :item
	delegate :codigo_descricao_unidade_codigo_da_prefeitura, to: :item
	delegate :descricao_tecnica, to: :item
	delegate :combustivel, to: :item

	scope :validos, -> { where(valido: true) }
	scope :por_unidade_com_quantidade, -> { joins(:itens_do_pedido_por_unidade_orcamentaria).where('licitacao_itens_do_pedido_por_unidade_orcamentaria.quantidade is not null AND licitacao_itens_do_pedido_por_unidade_orcamentaria.quantidade > 0 AND licitacao_itens_do_pedido.por_valor_previsto = false').distinct }
	scope :por_unidade_com_valor_previsto, -> { where('licitacao_itens_do_pedido.por_valor_previsto = true') }
	scope :quantidade_maior_que_zero, -> { joins(:itens_do_pedido_por_unidade_orcamentaria).where('licitacao_itens_do_pedido_por_unidade_orcamentaria.quantidade is not null AND licitacao_itens_do_pedido_por_unidade_orcamentaria.quantidade >= 0 AND licitacao_itens_do_pedido.por_valor_previsto = false').distinct }
	scope :por_desconto_ou_taxa, -> { where('tipo = 1 OR tipo = 2') }

	before_save :atribui_valor_previsto_ao_item
	enum tipo: {
		por_preco: 0,
		por_desconto: 1,
		por_taxa: 2
	}

	after_initialize :inicializa_itens_do_pedido_por_unidade_orcamentaria, if: :new_record?

	def inicializa_itens_do_pedido_por_unidade_orcamentaria
		if self.new_record?
			if self.pedido && self.itens_do_pedido_por_unidade_orcamentaria.empty?
				unidade_por_pedido = pedido.unidades_orcamentarias_por_pedido.find_by(unidade_orcamentaria_id: self.pedido.unidade_orcamentaria.id)
				self.itens_do_pedido_por_unidade_orcamentaria.build(unidade_orcamentaria_por_pedido_id: unidade_por_pedido.id) unless unidade_por_pedido.nil?
			end
		end
	end

	def pode_ser_anulado?
		(pedido.projeto_simplificado.blank? && pedido.coleta_de_preco?) || (pedido.projeto_simplificado.present? && !pedido.fechado? && !pedido.projeto_gerado?)
	end

	def valida_se_item_simplificado_possui_preco_estimativo
		if self.pedido.projeto_simplificado? && (self.try(:preco_estimativo).blank? ||self.try(:preco_estimativo) == 0)
			errors.add(:preco_estimativo, "Não é um valor válido")
		end
	end

	# def por_valor_previsto?
	# 	unidade = self.pedido.unidades_orcamentarias_por_pedido.find_by(unidade_orcamentaria_id: self.pedido.unidade_orcamentaria.id)
	# 	if unidade.present?
	# 		item_por_unidade = self.itens_do_pedido_por_unidade_orcamentaria.find_by("unidade_orcamentaria_por_pedido_id = ?", unidade.id)
	# 		if item_por_unidade.present?
	# 			item_por_unidade.valor_previsto_desconto.present? && item_por_unidade.valor_previsto_desconto > 0
	# 		end
	# 	end
	# end

	def classifica_valores_dos_itens quantidade
		self.itens_do_pedido_por_pessoa.validos.order('preco_de_cotacao asc').pluck(:preco_de_cotacao).first(quantidade)
	end

	def valor_total_projeto_simplificado
		quantidade_total_requisitada.to_f * preco_estimativo.to_f
	end

	def valor_total_projeto_simplificado_por_unidade unidade_orcamentaria_id
		quantidade_por_unidade_orcamentaria(unidade_orcamentaria_id) * preco_estimativo
	end

	def media_menores_valores_dos_itens quantidade
		classifica_valores_dos_itens(quantidade).sum / quantidade
	end

	def quantidade_total_requisitada
		return 1 if self.por_valor_previsto?

		(itens_do_pedido_por_unidade_orcamentaria.sum(:quantidade) * self.periodicidade_principal).to_f
	end

	def quantidade_total_requisitada_sem_periodicidade
		return 1 if self.por_valor_previsto?

		itens_do_pedido_por_unidade_orcamentaria.sum(:quantidade).to_f
	end

	def valor_total_previsto_por_desconto
		itens_do_pedido_por_unidade_orcamentaria.sum(:valor_previsto_desconto).to_f
	end

	def valor_total_previsto_por_preco_e_valor_previsto
		(itens_do_pedido_por_unidade_orcamentaria.sum(:valor_previsto_desconto).to_d + self.pedido.itens_do_pedido.sum(:menor_preco).to_d).to_f
	end

	def quantidade_por_unidade_orcamentaria unidade_orcamentaria_id
		if self.por_valor_previsto?
			return 1
		else
			itens_do_pedido_por_unidade_orcamentaria.joins(unidade_orcamentaria_por_pedido: :unidade_orcamentaria).where("loa_unidades_orcamentarias.id = ?", unidade_orcamentaria_id.try(:to_s)).sum(:quantidade) * self.periodicidade_principal
		end
	end

	def valor_previsto_por_unidade_orcamentaria unidade_orcamentaria_id
		itens_do_pedido_por_unidade_orcamentaria.joins(unidade_orcamentaria_por_pedido: :unidade_orcamentaria).where("loa_unidades_orcamentarias.id = ?", unidade_orcamentaria_id.to_s).sum(:valor_previsto_desconto)
	end

	def quantidade_por_unidade_orcamentaria_sem_periodicidade unidade_orcamentaria_id
		itens_do_pedido_por_unidade_orcamentaria.joins(unidade_orcamentaria_por_pedido: :unidade_orcamentaria).where("loa_unidades_orcamentarias.id = ?", unidade_orcamentaria_id.to_s).sum(:quantidade)
	end

	def periodicidade_por_unidade_orcamentaria unidade_orcamentaria_id
		item_da_unidade = itens_do_pedido_por_unidade_orcamentaria.joins(unidade_orcamentaria_por_pedido: :unidade_orcamentaria).where("loa_unidades_orcamentarias.id = ?", unidade_orcamentaria_id.to_s).first
		texto = ""
		texto << "#{item_da_unidade.periodicidade.to_s}" if item_da_unidade.periodicidade.present?
		texto << " (" + item_da_unidade.try(:unidade_de_medida).try(:descricao).to_s + ")"
		texto
	end

	def preco_medio
		qtd = itens_do_pedido_por_pessoa.validos.count
		if qtd > 0
			preco_medio_de_cotacao = (itens_do_pedido_por_pessoa.validos.sum(:preco_de_cotacao) / qtd).round(2)
			if self.por_valor_previsto? && self.por_desconto?
				preco_medio_de_cotacao += self.itens_do_pedido_por_unidade_orcamentaria.sum(&:valor_previsto_desconto)
			#elsif self.por_valor_previsto? && self.por_preco?
				#preco_medio_de_cotacao += self.itens_do_pedido_por_unidade_orcamentaria.sum(&:valor_previsto_desconto)
			end
		else
			preco_medio_de_cotacao = 0
		end
		return preco_medio_de_cotacao
	end

	def total_medio
		(preco_medio.to_d * quantidade_total_requisitada).round(2)
	end

	def menor_preco
		itens_do_pedido_por_pessoa.validos.minimum(:preco_de_cotacao).to_f
	end

	def maior_preco
		itens_do_pedido_por_pessoa.validos.maximum(:preco_de_cotacao).to_f
	end

	def menor_total
		(menor_preco * quantidade_total_requisitada).round(2)
	end

	def maior_desconto
		maior_preco
	end

	def fornecedor_do_menor_preco
		self.itens_do_pedido_por_pessoa.min_by(&:preco_de_cotacao).pessoa_do_pedido
	end

	def unidade_de_medida_da_periodicidade_principal
		if pedido.unidade_orcamentaria.present?
			item_da_unidade = itens_do_pedido_por_unidade_orcamentaria.joins(:unidade_orcamentaria_por_pedido).where('licitacao_unidades_orcamentarias_por_pedido.unidade_orcamentaria_id = ?', pedido.unidade_orcamentaria.id).first
			item_da_unidade.try(:unidade_de_medida)
		end
	end

	def periodicidade_principal
		if pedido.unidade_orcamentaria.present?
			item_da_unidade = itens_do_pedido_por_unidade_orcamentaria.joins(:unidade_orcamentaria_por_pedido).where('licitacao_unidades_orcamentarias_por_pedido.unidade_orcamentaria_id = ?', pedido.unidade_orcamentaria.id).first
			item_da_unidade.present? ? item_da_unidade.periodicidade : 1
		end
	end

	def periodicidade_e_unidade_de_medida
		item_da_unidade = itens_do_pedido_por_unidade_orcamentaria.joins(:unidade_orcamentaria_por_pedido).where('licitacao_unidades_orcamentarias_por_pedido.unidade_orcamentaria_id = ?', pedido.unidade_orcamentaria.id).first
		texto = ""
		texto << "#{item_da_unidade.periodicidade.to_s}" if item_da_unidade.present? && item_da_unidade.periodicidade.present?
		texto << " (" + item_da_unidade.try(:unidade_de_medida).try(:descricao).to_s + ")"
		texto
	end

	def atribui_valor_previsto_ao_item
		self.por_valor_previsto = self.itens_do_pedido_por_unidade_orcamentaria.sum(&:valor_previsto_desconto) > 0 || self.por_desconto?
	end

	def valida_nao_pode_ser_por_desconto
		if self.pedido.possui_periodicidade_nos_itens? && self.por_desconto?
			errors.add(:tipo, "Não pode ser por desconto caso pedido tenha periodicidade")
		end
	end

	def unidades_que_cotaram_item
		pedido.unidades_orcamentarias_por_pedido.joins(:itens_do_pedido_por_unidade_orcamentaria).where(
			licitacao_itens_do_pedido_por_unidade_orcamentaria: {item_do_pedido_id: id}
		)
	end

	def porcentagem_media_do_desconto
		(itens_do_pedido_por_pessoa.sum(&:desconto_de_cotacao) / itens_do_pedido_por_pessoa.size).round(2) rescue 0
	end

	def mediana
		cotacoes_itens_por_pessoa = itens_do_pedido_por_pessoa.validos.pluck(:preco_de_cotacao)
		return if cotacoes_itens_por_pessoa.empty?

		cotacoes_ordenadas = cotacoes_itens_por_pessoa.sort
		size = cotacoes_ordenadas.size

		if size.even?
			(cotacoes_ordenadas[size/2 - 1] + cotacoes_ordenadas[size/2]) / 2.0
		else
			cotacoes_ordenadas[size/2]
		end
	end

	def total_mediana
		(mediana.to_d * quantidade_total_requisitada).round(2)
	end

end
