class Licitacao::PessoaDoPedido < ApplicationRecord
	has_paper_trail
	include TradutorConcern

	attr_default :interno, true
	attr_default :valido, true

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

	belongs_to :pedido, class_name: 'Licitacao::Pedido', required: true
	belongs_to :pessoa, class_name: 'Base::Pessoa', required: true

	has_many :itens_do_pedido_por_pessoa, dependent: :destroy
	has_many :itens_do_pedido, through: :itens_do_pedido_por_pessoa
	has_many :solicitacoes_por_email, class_name: 'Licitacao::SolicitacaoPorEmail', dependent: :destroy
	has_one :documento_da_cotacao_do_pedido, class_name: 'Licitacao::DocumentoDaCotacaoDoPedido', dependent: :destroy

	has_attached_file :anexo_cotacao

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

	validates_presence_of :prazo_da_proposta, if: :itens_do_pedido_por_pessoa_preenchido?, on: :update
	validates_presence_of :motivo, unless: :valido?
	validates_presence_of :nome_do_responsavel, :tipo_de_responsavel, :data_de_cadastro_da_cotacao, if: :itens_do_pedido_por_pessoa_preenchido?, on: :update
	validates_presence_of :anexo_cotacao, if: Proc.new{ self.codigo_de_acesso.present? && !self.interno && itens_do_pedido_por_pessoa_preenchido? }, on: :update

	validates_uniqueness_of :cpf_do_responsavel, scope: [:pedido_id], message: "já existe cotação para o CPF informado", conditions: -> { where(valido: true) }, if: Proc.new{ self.valido? && self.cpf_do_responsavel.present? }
	validates_uniqueness_of :pessoa_id, scope: :pedido_id, if: Proc.new{ self.persisted? }, unless: :existe_pessoa_igual_ativa?

	validates_attachment_content_type :anexo_cotacao, content_type: ['text/plain', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/msword', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'image/gif', 'image/jpeg', 'image/png', 'image/bmp']
	validates_attachment_size :anexo_cotacao, in: 0..10.megabytes

	validates_associated :itens_do_pedido_por_pessoa
	validates_cpf :cpf_do_responsavel, allow_blank: true
	validate :existe_ao_menos_um_item_preenchido?, if: Proc.new{ self.itens_do_pedido_por_pessoa.any? && !(self.pedido.por_valor_previsto? && self.pedido.todos_os_itens_por_preco?)}

	scope :validos, -> { where(valido: true) }
	scope :pessoas_que_cotaram_todos, -> { select(&:cotou_todos_itens?) }

	enum tipo_de_responsavel: TIPOS_DE_RESPONSAVEIS

	def valor_total_cotacao
		if itens_do_pedido_por_pessoa.empty?
			return 0
		else
			itens_validos_e_por_valor_previsto = itens_do_pedido_por_pessoa.validos_e_por_valor_previsto
			itens_por_quantidade = self.itens_do_pedido_por_pessoa.validos_e_por_quantidade

			itens_por_valor_previsto_desconto = itens_validos_e_por_valor_previsto
				.joins(:item_do_pedido)
					.where(licitacao_itens_do_pedido: {tipo: Licitacao::ItemDoPedido.tipos["por_desconto"]} )

			itens_por_valor_previsto_taxa = itens_validos_e_por_valor_previsto
				.joins(:item_do_pedido)
					.where(licitacao_itens_do_pedido: {tipo: Licitacao::ItemDoPedido.tipos["por_taxa"]} )

			itens_por_valor_previsto_preco = itens_validos_e_por_valor_previsto
				.joins(:item_do_pedido)
					.where(licitacao_itens_do_pedido: {tipo: Licitacao::ItemDoPedido.tipos["por_preco"]} )

			valor_total_por_taxa = 0
			itens_por_valor_previsto_taxa.each do |item|
				porcentagem = (item.total_por_desconto * item.preco_de_cotacao)/100
				valor_total_por_taxa += item.total_por_desconto + porcentagem
			end

			return itens_por_valor_previsto_desconto.sum(&:total_por_desconto) + itens_por_valor_previsto_preco.sum(&:total_valor_previsto_por_preco) + itens_por_quantidade.sum(&:total) + valor_total_por_taxa.to_d
		end
	end

	def total_da_cotacao
		if itens_do_pedido_por_pessoa.empty?
			0
		else
			itens_do_pedido_por_pessoa.inject(0) { |total, item_do_pedido_por_pessoa|
				total + (item_do_pedido_por_pessoa.item_do_pedido.por_valor_previsto == true ? item_do_pedido_por_pessoa.item_do_pedido.valor_total_previsto_por_desconto : (item_do_pedido_por_pessoa.preco_de_cotacao * item_do_pedido_por_pessoa.item_do_pedido.quantidade_total_requisitada_sem_periodicidade))
			}
		end
	end

	def total_da_cotacao_por_quantidade
		itens_do_pedido_por_pessoa.validos_e_por_quantidade.inject(0) { |total, item_por_pessoa|
			total + item_por_pessoa.total
		}
	end

	def total_da_cotacao_menor_preco
		itens_do_pedido_por_pessoa.validos_e_por_preco.inject(0) { |total, item_por_pessoa|
			total + (item_por_pessoa.preco_de_cotacao.to_f == item_por_pessoa.item_do_pedido.menor_preco.to_f ? item_por_pessoa.total : 0)
		}
	end

	def total_da_cotacao_por_preco
		itens_do_pedido_por_pessoa.validos_e_por_preco.inject(0) { |total, item_por_pessoa|
			total + item_por_pessoa.total
		}
	end

	def total_da_cotacao_por_preco_valor_previsto
		itens_do_pedido_por_pessoa.validos_e_por_preco.inject(0) { |total, item_por_pessoa|
			total + item_por_pessoa.total_por_desconto
		}
	end

	def total_da_cotacao_por_desconto
		itens_do_pedido_por_pessoa.validos_e_por_desconto.inject(0) { |total, item_por_pessoa|
			total + item_por_pessoa.total_por_desconto
		}
	end

	# BOOLEANS
	def existe_pessoa_igual_ativa?
		Licitacao::PessoaDoPedido.where(pedido_id: pedido_id).where(valido: true)
	end

	def cotado?
		itens_do_pedido_por_pessoa.any? && itens_do_pedido_por_pessoa.first.persisted?
	end

	def cotou_todos_itens?
		itens_validos = pedido.itens_do_pedido.validos.order(:id)
		itens_cotados = itens_do_pedido_por_pessoa.validos.order(:id).map(&:item_do_pedido)
		itens_validos.size == itens_cotados.size
	end

	def cotou_itens_por_preco?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_preco? && item.persisted? }.any?
		end
	end

	def cotou_itens_por_desconto?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_desconto? && item.persisted? }.any?
		end
	end

	def cotou_itens_por_preco_e_por_desconto?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_preco? && item.persisted? }.any? &&
				itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_desconto? && item.persisted? }.any?
		end
	end

	def cotou_itens_por_valor_previsto?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_valor_previsto == true && item.persisted? }.any?
		end
	end

	def cotou_itens_por_preco_e_valor_previsto?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_valor_previsto == true && item.item_do_pedido.por_preco? && item.persisted? }.any?
		end
	end

	def cotou_itens_por_quantidade?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item_do_pedido.por_valor_previsto == false && item.persisted? }.any?
		end
	end

	def cotou_itens_por_valor_e_quantidade?
		if itens_do_pedido_por_pessoa.any?
			itens_do_pedido_por_pessoa.to_a.select{ |item| item.item.item_do_pedido.por_valor_previsto? && item.persisted? }.any? &&
				itens_do_pedido_por_pessoa.to_a.select{ |item| !item.item_do_pedido.por_valor_previsto? && item.persisted? }.any?
		end
	end

	def convidar
		if self.persisted? && pessoa.email.present?
			data_expiracao = Date.today + Configuracao.last.tempo_limite_da_cotacao
			gerar_codigo_de_acesso(data_expiracao)
			@emails = [pessoa.email, pessoa.email_alternativo]
			@emails.each do |email|
				unless email.blank?
					PrincipalMailer.solicitar_cotacao( self.id, email ).deliver_later unless Rails.env.development? || Rails.env.test?
					solicitacoes_por_email.create(data_de_envio: DateTime.now, email: email, data_de_expiracao: data_expiracao, codigo_de_acesso: self.codigo_de_acesso)
				end
			end
		end
	end

	def confirmar_cotacao previamente_cotado = false
		if self.persisted? && pessoa.email.present?
			PrincipalMailer.confirmar_cotacao(self.id, previamente_cotado).deliver_now unless Rails.env.development? || Rails.env.test?
		end
	end

	def atualiza_solicitacao_de_email
		solicitacoes_por_email.find_by(codigo_de_acesso: self.codigo_de_acesso).update_columns(respondido: true, data_de_cotacao: DateTime.now)
	end

	def inicia_cotacao
		self.pedido.itens_do_pedido.validos.each {|item_do_pedido|
			if self.itens_do_pedido_por_pessoa.select{|ippp| ippp.item_do_pedido_id == item_do_pedido.id}.empty?
				self.itens_do_pedido_por_pessoa.build(item_do_pedido_id: item_do_pedido.id)
			end
		}
	end

	def existe_ao_menos_um_item_preenchido?
		if self.pedido.por_valor_previsto?
			errors.add(:base, "Deve ser preenchido pelo menos um item") unless self.itens_do_pedido_por_pessoa.any? { |ipp| ipp.preco_de_cotacao > 0 }
		else
			errors.add(:base, "Deve ser preenchido pelo menos um item") if self.itens_do_pedido_por_pessoa.all? { |ipp| ipp.marca.blank? && ipp.preco_de_cotacao.to_d <= 0} || self.itens_do_pedido_por_pessoa.map{ |ipp| ipp.item.categoria.try(:tipo).to_s == "serviço" && ipp.preco_de_cotacao.to_d > 0 }.size == 0
		end
	end

	def fornecedor_tem_menor_cotacao?
		itens_do_pedido_por_pessoa.each do |item_do_pedido_por_pessoa|
			return true if item_do_pedido_por_pessoa.preco_de_cotacao.to_f.round(2) == item_do_pedido_por_pessoa.item_do_pedido.menor_preco.to_f.round(2)
		end
		return false
	end

	def fornecedor_tem_maior_cotacao?
		itens_do_pedido_por_pessoa.each do |item_do_pedido_por_pessoa|
			return true if item_do_pedido_por_pessoa.preco_de_cotacao.to_f.round(2) == item_do_pedido_por_pessoa.item_do_pedido.maior_preco.to_f.round(2)
		end
		return false
	end

	def data_envio_do_email_enviar_cotacao
		if solicitacoes_por_email.any?
			solicitacoes_por_email.last.data_de_envio
		else
			validade_codigo_de_acesso - Configuracao.last.tempo_limite_da_cotacao
		end
	end

	def preco_de_cotacao_total
		itens_do_pedido_por_pessoa.sum { |item| item.preco_de_cotacao.to_d }
	end

	private
	def gerar_codigo_de_acesso data_de_expiracao
		codigo_de_acesso = SecureRandom.base64(16).gsub("/","_").gsub(/=+$/,"")
		update_columns(codigo_de_acesso: codigo_de_acesso, validade_codigo_de_acesso: data_de_expiracao)
	end

	def itens_do_pedido_por_pessoa_preenchido?
		self.itens_do_pedido_por_pessoa.each do |item_do_pedido_por_pessoa|
			return true if  item_do_pedido_por_pessoa.preco_de_cotacao.to_f > 0 && ( !item_do_pedido_por_pessoa.marca.blank? || item_do_pedido_por_pessoa.item_do_pedido.por_valor_previsto? )
		end
		return false
	end
end
