# frozen_string_literal: true
require "value_semantics/monkey_patched"
require_relative "tts_template"
require_relative "low_balance"
class CallAttempt
def self.for(customer, rate, usage, trust_level, direction:, **kwargs)
kwargs.merge!(direction: direction)
credit = [customer.minute_limit.to_d - usage, 0].max + customer.balance
if !rate || !trust_level.support_call?(rate)
Unsupported.new(direction: direction)
elsif credit < rate * 10
NoBalance.for(customer, rate, usage, trust_level, **kwargs)
else
for_ask_or_go(customer, rate, usage, credit, **kwargs)
end
end
def self.for_ask_or_go(customer, rate, usage, credit, digits: nil, **kwargs)
kwargs.merge!(
customer_id: customer.customer_id,
limit_remaining: limit_remaining(customer, usage, rate),
max_minutes: (credit / rate).to_i
)
if digits != "1" && limit_remaining(customer, usage, rate) < 10
AtLimit.new(**kwargs)
else
new(**kwargs)
end
end
def self.limit_remaining(customer, usage, rate)
can_use = customer.minute_limit.to_d + customer.monthly_overage_limit
([can_use - usage, 0].max / rate).to_i
end
value_semantics do
customer_id String
from String
to(/\A\+\d+\Z/)
call_id String
direction Either(:inbound, :outbound)
limit_remaining Integer
max_minutes Integer
end
def to_render
["#{direction}/connect", { locals: to_h }]
end
def create_call(fwd, *args, &block)
fwd.create_call(*args, &block)
end
def as_json(*)
{
from: from,
to: to,
customer_id: customer_id,
limit_remaining: limit_remaining,
max_minutes: max_minutes
}
end
def to_json(*args)
as_json.to_json(*args)
end
class Unsupported
value_semantics do
direction Either(:inbound, :outbound)
end
def view
"#{direction}/unsupported"
end
def tts
TTSTemplate.new(view).tts(self)
end
def to_render
[view]
end
def create_call(*); end
def as_json(*)
{ tts: tts }
end
def to_json(*args)
as_json.to_json(*args)
end
end
class NoBalance
def self.for(customer, rate, usage, trust_level, direction:, **kwargs)
LowBalance.for(customer).then(&:notify!).then do |amount|
if amount&.positive?
CallAttempt.for(
customer.with_balance(customer.balance + amount),
rate, usage, trust_level, direction: direction, **kwargs
)
else
NoBalance.new(balance: customer.balance, direction: direction)
end
end
end
value_semantics do
balance Numeric
direction Either(:inbound, :outbound)
end
def view
"#{direction}/no_balance"
end
def tts
TTSTemplate.new(view).tts(self)
end
def to_render
[view, { locals: to_h }]
end
def create_call(*); end
def as_json(*)
{ tts: tts }
end
def to_json(*args)
as_json.to_json(*args)
end
end
class AtLimit
value_semantics do
customer_id String
from String
to(/\A\+\d+\Z/)
call_id String
direction Either(:inbound, :outbound)
limit_remaining Integer
max_minutes Integer
end
def view
"#{direction}/at_limit"
end
def tts
TTSTemplate.new(view).tts(self)
end
def to_render
[view, { locals: to_h }]
end
def create_call(fwd, *args, &block)
fwd.create_call(*args, &block)
end
def as_json(*)
{
tts: tts,
from: from,
to: to,
customer_id: customer_id,
limit_remaining: limit_remaining,
max_minutes: max_minutes
}
end
def to_json(*args)
as_json.to_json(*args)
end
end
end