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