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