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