# frozen_string_literal: true

require "simplecov"
SimpleCov.start do
	add_filter "/test/"
	enable_coverage :branch
end

require "minitest/autorun"
require "webmock/minitest"

begin
	require "pry-rescue/minitest"
	require "pry-reload"

	module Minitest
		class Test
			alias old_capture_exceptions capture_exceptions
			def capture_exceptions
				old_capture_exceptions do
					yield
				rescue Minitest::Skip => e
					failures << e
				end
			end
		end
	end
rescue LoadError
	# Just helpers for dev, no big deal if missing
	nil
end

$VERBOSE = nil
ARGV[0] = "component"

class FakeRedis
	def initialize(values={})
		@values = values
	end

	def reset!(values={})
		@values = values
	end

	def set(key, value, *)
		@values[key] = value
		EMPromise.resolve("OK")
	end

	def setex(key, _expiry, value)
		set(key, value)
	end

	def del(*keys)
		keys.each { |key| @values.delete(key) }
	end

	def mget(*keys)
		EMPromise.all(keys.map(&method(:get)))
	end

	def get(key)
		EMPromise.resolve(@values[key])
	end

	def getbit(key, bit)
		get(key).then { |v| v.to_i.to_s(2)[bit].to_i }
	end

	def bitfield(key, *ops)
		get(key).then do |v|
			bits = v.to_i.to_s(2)
			ops.each_slice(3).map do |(op, encoding, offset)|
				raise "unsupported bitfield op" unless op == "GET"
				raise "unsupported bitfield op" unless encoding == "u1"

				bits[offset].to_i
			end
		end
	end

	def hget(key, field)
		@values.dig(key, field)
	end

	def hincrby(key, field, incrby)
		@values[key] ||= {}
		@values[key][field] ||= 0
		@values[key][field] += incrby
	end

	def sadd(key, member)
		@values[key] ||= Set.new
		@values[key] << member
	end

	def srem(key, member)
		@values[key].delete(member)
	end

	def scard(key)
		@values[key]&.size || 0
	end

	def expire(_, _); end

	def exists(*keys)
		EMPromise.resolve(
			@values.select { |k, _| keys.include? k }.size.to_s
		)
	end

	def lindex(key, index)
		get(key).then { |v| v&.fetch(index) }
	end

	def lrange(key, sindex, eindex)
		get(key).then { |v| v ? v[sindex..eindex] : [] }
	end

	def rpush(key, *values)
		@values[key] ||= []
		values.each { |v| @values[key].push(v) }
	end
end

REDIS = FakeRedis.new

module Minitest
	class Test
		def self.em(m)
			alias_method "raw_#{m}", m
			define_method(m) do
				$panic = nil
				e = nil
				EM.run do
					Fiber.new {
						begin
							send("raw_#{m}")
						rescue
							e = $!
						ensure
							EM.stop
						end
					}.resume
				end
				raise e if e
			end
		end
	end
end
