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		).then do |result|
 54			log.info "ending_call #{customer_id} #{call_id}", result
 55		end
 56	end
 57
 58protected
 59
 60	def find(customer, other_tel, direction:, **kwargs)
 61		find_all(customer, other_tel, direction).then do |(rate, usage, tl, c)|
 62			CallAttempt.for(
 63				customer: customer, rate: rate, usage: usage,
 64				supported:
 65					rate &&
 66					tl.support_call?(rate, c || 0) &&
 67					other_tel !~ /\A\+?1?[94]11\Z/,
 68				direction: direction, **kwargs
 69			)
 70		end
 71	end
 72
 73	def find_all(customer, other_tel, direction)
 74		EMPromise.all([
 75			find_rate(customer.plan_name, other_tel, direction),
 76			find_usage(customer.customer_id),
 77			TrustLevelRepo.new(db: db, redis: redis).find(customer),
 78			redis.scard("jmp_customer_ongoing_calls-#{customer.customer_id}")
 79		])
 80	end
 81
 82	def find_usage(customer_id)
 83		db.query_one(<<~SQL, customer_id, default: { a: 0 }).then { |r| r[:a] }
 84			SELECT COALESCE(SUM(charge), 0) AS a FROM cdr_with_charge
 85			WHERE
 86				customer_id=$1 AND
 87				start > DATE_TRUNC('month', LOCALTIMESTAMP)
 88		SQL
 89	end
 90
 91	def find_rate(plan_name, other_tel, direction)
 92		# || CAD temporary for transitional accounts
 93		promise = db.query_one(<<~SQL, plan_name || "CAD", other_tel, direction)
 94			SELECT rate FROM call_rates
 95			WHERE
 96				plan_name=$1 AND
 97				$2 LIKE prefix || '%' AND
 98				direction=$3
 99			ORDER BY prefix DESC
100			LIMIT 1
101		SQL
102		promise.then { |row| row&.dig(:rate) }
103	end
104end