# frozen_string_literal: true

require "em_promise"
require "money/bank/open_exchange_rates_bank"

require_relative "bull_bitcoin"
require_relative "em"
require_relative "simple_swap"

class CryptoSellPrices
	class PriceError < StandardError; end

	def initialize(redis, oxr_app_id, bull: BullBitcoin.new)
		@redis = redis
		@bull = bull
		@oxr = Money::Bank::OpenExchangeRatesBank.new(
			Money::RatesStore::Memory.new
		)
		@oxr.app_id = oxr_app_id
	end

	def usd
		EMPromise.all([cad, cad_to_usd]).then { |(a, b)| a * b }
	end

protected

	def cad_to_usd
		@redis.get("cad_to_usd").then do |rate|
			next rate.to_f if rate

			EM.promise_defer {
				# OXR gem is not async, so defer to threadpool
				@oxr.update_rates
				@oxr.get_rate("CAD", "USD")
			}.then do |orate|
				@redis.setex("cad_to_usd", 60 * 60, orate).then { orate }
			end
		end
	end
end

class BCHSellPrices < CryptoSellPrices
	def initialize(
		redis, oxr_app_id,
		simple_swap: SimpleSwap.new, bull: BullBitcoin.new
	)
		super(redis, oxr_app_id, bull: bull)
		@simple_swap = simple_swap
	end

	def cad
		EMPromise.all([
			@bull.fetch_btc_cad,
			@simple_swap.fetch_rate("btc")
		]).then do |(btc_cad, bch_per_btc)|
			unless bch_per_btc&.positive?
				raise PriceError, "SimpleSwap BTC to BCH rate was not positive"
			end

			btc_cad / bch_per_btc
		end
	end
end

class BTCSellPrices < CryptoSellPrices
	def cad
		@bull.fetch_btc_cad
	end
end
