1# frozen_string_literal: true
2
3require "value_semantics/monkey_patched"
4
5require_relative "tts_template"
6require_relative "low_balance"
7
8class CallAttempt
9 EXPENSIVE_ROUTE = {
10 "usd_beta_unlimited-v20210223" => 0.9,
11 "cad_beta_unlimited-v20210223" => 1.1
12 }.freeze
13
14 def self.for(customer, rate, usage, direction:, **kwargs)
15 kwargs.merge!(direction: direction)
16 included_credit = [customer.minute_limit.to_d - usage, 0].max
17 if !rate || rate >= EXPENSIVE_ROUTE.fetch(customer.plan_name, 0.1)
18 Unsupported.new(direction: direction)
19 elsif included_credit + customer.balance < rate * 10
20 NoBalance.for(customer, rate, usage, **kwargs)
21 else
22 for_ask_or_go(customer, rate, usage, **kwargs)
23 end
24 end
25
26 def self.for_ask_or_go(customer, rate, usage, digits: nil, **kwargs)
27 can_use = customer.minute_limit.to_d + customer.monthly_overage_limit
28 kwargs.merge!(customer_id: customer.customer_id)
29 if digits != "1" && can_use - usage < rate * 10
30 AtLimit.new(**kwargs)
31 else
32 new(**kwargs)
33 end
34 end
35
36 value_semantics do
37 customer_id String
38 from String
39 to(/\A\+\d+\Z/)
40 call_id String
41 direction Either(:inbound, :outbound)
42 end
43
44 def to_render
45 ["#{direction}/connect", { locals: to_h }]
46 end
47
48 def create_call(fwd, *args, &block)
49 fwd.create_call(*args, &block)
50 end
51
52 def as_json(*)
53 {
54 from: from,
55 to: to,
56 customer_id: customer_id
57 }
58 end
59
60 def to_json(*args)
61 as_json.to_json(*args)
62 end
63
64 class Unsupported
65 value_semantics do
66 direction Either(:inbound, :outbound)
67 end
68
69 def view
70 "#{direction}/unsupported"
71 end
72
73 def tts
74 TTSTemplate.new(view).tts(self)
75 end
76
77 def to_render
78 [view]
79 end
80
81 def create_call(*); end
82
83 def as_json(*)
84 { tts: tts }
85 end
86
87 def to_json(*args)
88 as_json.to_json(*args)
89 end
90 end
91
92 class NoBalance
93 def self.for(customer, rate, usage, direction:, **kwargs)
94 LowBalance.for(customer).then(&:notify!).then do |amount|
95 if amount&.positive?
96 CallAttempt.for(
97 customer.with_balance(customer.balance + amount),
98 rate, usage, direction: direction, **kwargs
99 )
100 else
101 NoBalance.new(balance: customer.balance, direction: direction)
102 end
103 end
104 end
105
106 value_semantics do
107 balance Numeric
108 direction Either(:inbound, :outbound)
109 end
110
111 def view
112 "#{direction}/no_balance"
113 end
114
115 def tts
116 TTSTemplate.new(view).tts(self)
117 end
118
119 def to_render
120 [view, { locals: to_h }]
121 end
122
123 def create_call(*); end
124
125 def as_json(*)
126 { tts: tts }
127 end
128
129 def to_json(*args)
130 as_json.to_json(*args)
131 end
132 end
133
134 class AtLimit
135 value_semantics do
136 customer_id String
137 from String
138 to(/\A\+\d+\Z/)
139 call_id String
140 direction Either(:inbound, :outbound)
141 end
142
143 def view
144 "#{direction}/at_limit"
145 end
146
147 def tts
148 TTSTemplate.new(view).tts(self)
149 end
150
151 def to_render
152 [view, { locals: to_h }]
153 end
154
155 def create_call(fwd, *args, &block)
156 fwd.create_call(*args, &block)
157 end
158
159 def as_json(*)
160 {
161 tts: tts,
162 from: from,
163 to: to,
164 customer_id: customer_id
165 }
166 end
167
168 def to_json(*args)
169 as_json.to_json(*args)
170 end
171 end
172end