1# frozen_string_literal: true
 2
 3require "value_semantics/monkey_patched"
 4require "lazy_object"
 5
 6require_relative "call_attempt"
 7require_relative "trust_level_repo"
 8
 9class CallAttemptRepo
10	value_semantics do
11		db    Anything(), default: LazyObject.new { DB }
12		redis Anything(), default: LazyObject.new { REDIS }
13	end
14
15	def find_outbound(customer, to, **kwargs)
16		find(
17			customer,
18			to,
19			direction: :outbound,
20			from: customer.registered?.phone,
21			to: to,
22			**kwargs
23		)
24	end
25
26	def find_inbound(customer, from, **kwargs)
27		find(
28			customer,
29			from,
30			direction: :inbound,
31			from: from,
32			to: customer.registered?.phone,
33			**kwargs
34		)
35	end
36
37	def starting_call(customer, call_id)
38		redis.sadd(
39			"jmp_customer_ongoing_calls-#{customer.customer_id}",
40			call_id
41		).then do
42			redis.expire(
43				"jmp_customer_ongoing_calls-#{customer.customer_id}",
44				60 * 60
45			)
46		end
47	end
48
49	def ending_call(customer_id, call_id)
50		redis.srem(
51			"jmp_customer_ongoing_calls-#{customer_id}",
52			call_id
53		)
54	end
55
56protected
57
58	def find(customer, other_tel, direction:, **kwargs)
59		find_all(customer, other_tel, direction).then do |(rate, usage, tl, c)|
60			CallAttempt.for(
61				customer: customer, rate: rate, usage: usage,
62				supported: rate && tl.support_call?(rate, c || 0),
63				direction: direction, **kwargs
64			)
65		end
66	end
67
68	def find_all(customer, other_tel, direction)
69		EMPromise.all([
70			find_rate(customer.plan_name, other_tel, direction),
71			find_usage(customer.customer_id),
72			TrustLevelRepo.new(db: db, redis: redis).find(customer),
73			redis.scard("jmp_customer_ongoing_calls-#{customer.customer_id}")
74		])
75	end
76
77	def find_usage(customer_id)
78		db.query_one(<<~SQL, customer_id, default: { a: 0 }).then { |r| r[:a] }
79			SELECT COALESCE(SUM(charge), 0) AS a FROM cdr_with_charge
80			WHERE
81				customer_id=$1 AND
82				start > DATE_TRUNC('month', LOCALTIMESTAMP)
83		SQL
84	end
85
86	def find_rate(plan_name, other_tel, direction)
87		# || CAD temporary for transitional accounts
88		promise = db.query_one(<<~SQL, plan_name || "CAD", other_tel, direction)
89			SELECT rate FROM call_rates
90			WHERE
91				plan_name=$1 AND
92				$2 LIKE prefix || '%' AND
93				direction=$3
94			ORDER BY prefix DESC
95			LIMIT 1
96		SQL
97		promise.then { |row| row&.dig(:rate) }
98	end
99end