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