1# frozen_string_literal: true
  2
  3require "value_semantics/monkey_patched"
  4require_relative "../admin_action"
  5require_relative "../form_to_h"
  6
  7class AdminAction
  8	class NumberChange < AdminAction
  9		include Isomorphic
 10		class Command
 11			using FormToH
 12
 13			def self.for(target_customer, reply:)
 14				EMPromise.resolve(
 15					new(
 16						customer_id: target_customer.customer_id,
 17						old_tel: target_customer.registered?.phone
 18					)
 19				).then { |x|
 20					reply.call(x.form).then(&x.method(:change))
 21				}
 22			end
 23
 24			def initialize(**bag)
 25				@bag = bag
 26			end
 27
 28			def form
 29				FormTemplate.render("admin_number_change")
 30			end
 31
 32			def change(result)
 33				AdminAction::NumberChange.for(
 34					**@bag,
 35					**result.form.to_h
 36						.reject { |_k, v| v == "nil" }.transform_keys(&:to_sym)
 37				)
 38			end
 39		end
 40
 41		NilKey = Struct.new(:key) {
 42			def to_s
 43				"Expected a key with a value, but #{key} has no value."
 44			end
 45		}
 46
 47		def customer_id
 48			@attributes[:customer_id]
 49		end
 50
 51		def old_tel
 52			@attributes[:old_tel]
 53		end
 54
 55		def new_tel
 56			@attributes[:new_tel]
 57		end
 58
 59		def should_delete?
 60			["1", "true"].include?(@attributes[:should_delete])
 61		end
 62
 63		def check_forward
 64			EMPromise.all([
 65				check_noop,
 66				check_exist
 67			])
 68		end
 69
 70		def forward
 71			TrivialBackendSgxRepo.new(redis: REDIS).get(customer_id).then do |sgx|
 72				EMPromise.all([
 73					REDIS.rename("catapult_fwd-#{old_tel}", "catapult_fwd-#{new_tel}"),
 74					sgx.register!(new_tel),
 75					should_delete? && first_time? ? disconnect_number : nil
 76				]).then { self }
 77			end
 78		end
 79
 80		def to_reverse
 81			with(
 82				old_tel: new_tel,
 83				new_tel: old_tel
 84			)
 85		end
 86
 87		def to_s
 88			"number_change(#{customer_id}): #{old_tel} -> #{new_tel}#{delete_warning}"
 89		end
 90
 91	protected
 92
 93		def disconnect_number
 94			# Order name is limited to 40 characters
 95			# Assuming 12 chars for new_tel and 12 for customer_id, this is tight
 96			# but ok
 97			BandwidthTnRepo.new.disconnect(
 98				old_tel,
 99				"cust #{customer_id} swap to #{new_tel}"
100			)
101		end
102
103		def delete_warning
104			return "" unless should_delete? && !first_time?
105
106			" * NOT DELETING"
107		end
108
109		def check_noop
110			EMPromise.reject(NoOp.new) if new_tel == old_tel
111		end
112
113		def check_exist
114			cat_jid = "catapult_jid-#{old_tel}"
115			REDIS.exists(cat_jid).then { |v|
116				EMPromise.reject(NilKey.new(cat_jid)) unless v == 1
117			}
118		end
119	end
120end