# frozen_string_literal: true

module SentryOugai
	def _log(severity, *args)
		severity ||= Ougai::UNKNOWN
		append(severity, block_given? ? yield : args)
	end

	def super_add(severity, data)
		super unless level > severity
		return unless Sentry.get_current_hub

		level = Sentry::Breadcrumb::SentryLogger::LEVELS.fetch(severity, nil)
		Sentry.add_breadcrumb(Sentry::Breadcrumb.new(
			level: level,
			category: data[:category] || "logger",
			message: data[:msg],
			data: data.reject { |k, _| [:msg, :category].include?(k) },
			type: severity >= 3 ? "error" : level
		))
	end
end

LOG.extend SentryOugai

module SentryEMHiredis
	def respond_to_missing?(*)
		super
	end

	def record_span(description)
		transaction = Sentry.get_current_scope.get_transaction
		return yield unless transaction&.sampled

		span = transaction.start_child(
			op: "db.redis.command",
			description: description
		)

		df = yield
		df.callback { span.finish }
		df
	end

	def method_missing(sym, *args)
		EM::Hiredis.logger.debug(
			"Sending Redis command",
			category: "db.redis.command",
			commands: [{
				command: sym.to_s.upcase,
				key: args.first,
				arguments: args[1..-1].join(" ")
			}]
		)
		record_span("#{sym} #{args.join(' ')}") { super }
	end
end

EM::Hiredis::Client.include SentryEMHiredis

module SentryIQManager
	def record_span(description)
		transaction = Sentry.get_current_scope.get_transaction
		return yield unless transaction&.sampled

		span = transaction.start_child(op: "xmpp.iq", description: description)

		yield.then { span.finish }.catch do |e|
			span.set_status("internal_error")
			span.finish
			EMPromise.reject(e)
		end
	end

	def stanza_description(stanza)
		node = stanza.respond_to?(:node) ? stanza.node : stanza.child&.name
		"iq #{stanza.type} #{stanza.to} #{node}"
	end

	def write(stanza, timeout: @timeout)
		# Outgoing IQ already logged by blather
		record_span(stanza_description(stanza)) { super }
	end
end

IQ_MANAGER.extend SentryIQManager
