1# frozen_string_literal: true
  2
  3require "delegate"
  4
  5module TrustLevel
  6	def self.for(plan_name:, settled_amount: 0, manual: nil)
  7		@levels.each do |level|
  8			tl = level.call(
  9				plan_name: plan_name,
 10				settled_amount: settled_amount,
 11				manual: manual
 12			)
 13			return manual ? Manual.new(tl) : tl if tl
 14		end
 15
 16		raise "No TrustLevel matched"
 17	end
 18
 19	def self.register(&maybe_mk)
 20		@levels ||= []
 21		@levels << maybe_mk
 22	end
 23
 24	class Manual < SimpleDelegator
 25		def to_s
 26			"Manual(#{super})"
 27		end
 28	end
 29
 30	class Tomb
 31		TrustLevel.register do |manual:, **|
 32			new if manual == "Tomb"
 33		end
 34
 35		# The maximum amount a user at Tomb trust level can top up.
 36		# @return [Integer] Always 0 for Tomb level.
 37		def max_top_up_amount
 38			0
 39		end
 40
 41		def write_cdr?
 42			false
 43		end
 44
 45		def support_call?(*)
 46			false
 47		end
 48
 49		def send_message?(*)
 50			false
 51		end
 52
 53		# Validates a credit card transaction for a Tomb trust level user.
 54		# Users at this level cannot make credit card transactions.
 55		# @param _amount [BigDecimal] The amount of the transaction (ignored).
 56		# @param _declines [Integer] The number of recent declines (ignored).
 57		# @raise [DeclinedError] Always raised to prevent transactions.
 58		def validate_credit_card_transaction!(_amount, _declines)
 59			# Give a more ambiguous error so they don't know they're tombed.
 60			raise DeclinedError
 61		end
 62
 63		def create_subaccount?(*)
 64			false
 65		end
 66
 67		def to_s
 68			"Tomb"
 69		end
 70	end
 71
 72	class Basement
 73		TrustLevel.register do |manual:, settled_amount:, **|
 74			new if manual == "Basement" || (!manual && settled_amount < 10)
 75		end
 76
 77		# The maximum amount a user at Basement trust level can top up.
 78		# @return [Integer]
 79		def max_top_up_amount
 80			35
 81		end
 82
 83		# The maximum number of credit card declines allowed for a Basement user
 84		# before further transactions are blocked.
 85		# @return [Integer]
 86		def max_declines
 87			2
 88		end
 89
 90		def write_cdr?
 91			true
 92		end
 93
 94		def support_call?(rate, concurrency)
 95			rate <= 0.02 && concurrency < 1
 96		end
 97
 98		def send_message?(messages_today)
 99			messages_today < 40
100		end
101
102		# Validates a credit card transaction for a Basement trust level user.
103		# @param amount [BigDecimal] The amount of the transaction.
104		# @param declines [Integer] The number of recent declines for the customer.
105		# @raise [DeclinedError] if the number of declines exceeds `max_declines`.
106		# @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
107		def validate_credit_card_transaction!(amount, declines)
108			raise DeclinedError.new(declines, max_declines) if declines > max_declines
109			return unless amount > max_top_up_amount
110
111			raise AmountTooHighError.new(amount, max_top_up_amount)
112		end
113
114		def create_subaccount?(already_have)
115			already_have < 2
116		end
117
118		def to_s
119			"Basement"
120		end
121	end
122
123	class Paragon
124		TrustLevel.register do |manual:, settled_amount:, **|
125			new if manual == "Paragon" || (!manual && settled_amount > 60)
126		end
127
128		# The maximum amount a user at Paragon trust level can top up.
129		# @return [Integer]
130		def max_top_up_amount
131			500
132		end
133
134		# The maximum number of credit card declines allowed for a Paragon user
135		# before further transactions are blocked.
136		# @return [Integer]
137		def max_declines
138			3
139		end
140
141		def write_cdr?
142			true
143		end
144
145		def support_call?(_, concurrency)
146			concurrency < 10
147		end
148
149		def send_message?(messages_today)
150			messages_today < 700
151		end
152
153		# Validates a credit card transaction for a Paragon trust level user.
154		# @param amount [BigDecimal] The amount of the transaction.
155		# @param declines [Integer] The number of recent declines for the customer.
156		# @raise [DeclinedError] if the number of declines exceeds `max_declines`.
157		# @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
158		def validate_credit_card_transaction!(amount, declines)
159			raise DeclinedError.new(declines, max_declines) if declines > max_declines
160			return unless amount > max_top_up_amount
161
162			raise AmountTooHighError.new(amount, max_top_up_amount)
163		end
164
165		def create_subaccount?(already_have)
166			already_have < 10
167		end
168
169		def to_s
170			"Paragon"
171		end
172	end
173
174	class Olympias
175		TrustLevel.register do |manual:, **|
176			new if manual == "Olympias"
177		end
178
179		def write_cdr?
180			true
181		end
182
183		def support_call?(*)
184			true
185		end
186
187		def send_message?(*)
188			true
189		end
190
191		# Validates a credit card transaction for an Olympias trust level user.
192		# Users at this level have no restrictions on credit card transactions through this method.
193		# @param _amount [BigDecimal] The amount of the transaction (ignored).
194		# @param _declines [Integer] The number of recent declines (ignored).
195		# @return [void]
196		def validate_credit_card_transaction!(*) end
197
198		def create_subaccount?(*)
199			true
200		end
201
202		def to_s
203			"Olympias"
204		end
205	end
206
207	class Customer
208		TrustLevel.register do |manual:, plan_name:, **|
209			if manual && manual != "Customer"
210				Sentry.capture_message("Unknown TrustLevel: #{manual}")
211			end
212
213			new(plan_name)
214		end
215
216		EXPENSIVE_ROUTE = {
217			"usd_beta_unlimited-v20210223" => 0.9,
218			"USD" => 0.9,
219			"cad_beta_unlimited-v20210223" => 1.1,
220			"CAD" => 1.1
221		}.freeze
222
223		def initialize(plan_name)
224			@max_rate = EXPENSIVE_ROUTE.fetch(plan_name, 0.1)
225		end
226
227		# The maximum amount a user at Customer trust level can top up.
228		# @return [Integer]
229		def max_top_up_amount
230			130
231		end
232
233		# The maximum number of credit card declines allowed for a Customer user
234		# before further transactions are blocked.
235		# @return [Integer]
236		def max_declines
237			2
238		end
239
240		def write_cdr?
241			true
242		end
243
244		def support_call?(rate, concurrency)
245			rate <= @max_rate && concurrency < 4
246		end
247
248		def send_message?(messages_today)
249			messages_today < 500
250		end
251
252		# Validates a credit card transaction for a Customer trust level user.
253		# @param amount [BigDecimal] The amount of the transaction.
254		# @param declines [Integer] The number of recent declines for the customer.
255		# @raise [DeclinedError] if the number of declines exceeds `max_declines`.
256		# @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
257		def validate_credit_card_transaction!(amount, declines)
258			raise DeclinedError.new(declines, max_declines) if declines > max_declines
259			return unless amount > max_top_up_amount
260
261			raise AmountTooHighError.new(amount, max_top_up_amount)
262		end
263
264		def create_subaccount?(already_have)
265			already_have < 2
266		end
267
268		def to_s
269			"Customer"
270		end
271	end
272end