1# frozen_string_literal: true
  2
  3require "bandwidth"
  4require "value_semantics/monkey_patched"
  5require "uri"
  6
  7class CustomerFwd
  8	class InfiniteTimeout < StandardError
  9		attr_reader :fwd
 10
 11		def initialize(fwd)
 12			super "Infinite timeout"
 13			@fwd = fwd
 14		end
 15	end
 16
 17	def self.for(uri:, timeout: nil, voicemail_enabled: :default)
 18		timeout = Timeout.for(timeout, voicemail_enabled: voicemail_enabled)
 19
 20		fwd = if uri
 21			if uri =~ /\Asip:(.*)@sip.cheogram.com\Z/
 22				uri = "xmpp:#{$1.gsub(/%([0-9A-F]{2})/i) { $1.to_i(16).chr }}"
 23			end
 24
 25			URIS.fetch(uri.split(":", 2).first&.to_sym) {
 26				raise "Unknown forward URI: #{uri}"
 27			}.new(uri: uri, timeout: timeout)
 28		end
 29
 30		fwd && !timeout.zero? ? fwd : None.new(uri: uri, timeout: timeout)
 31	end
 32
 33	class Timeout
 34		def self.for(s, voicemail_enabled: :default)
 35			return Infinite.new unless voicemail_enabled
 36
 37			if s.nil? || s.is_a?(Infinite) || s.to_i.negative?
 38				return new(25) if voicemail_enabled == true # ~5s / ring, 5 rings
 39
 40				return Infinite.new
 41			end
 42
 43			return s if s.is_a?(self)
 44
 45			new(s)
 46		end
 47
 48		def initialize(s)
 49			@timeout = [s.to_i, 300].min
 50		end
 51
 52		def zero?
 53			@timeout.zero?
 54		end
 55
 56		def infinite?
 57			false
 58		end
 59
 60		def to_i
 61			@timeout
 62		end
 63
 64		def to_s
 65			to_i.to_s
 66		end
 67
 68		def as_json(*)
 69			to_i
 70		end
 71
 72		def to_json(*args)
 73			as_json.to_json(*args)
 74		end
 75
 76		class Infinite < Timeout
 77			def initialize; end
 78
 79			def zero?
 80				false
 81			end
 82
 83			def infinite?
 84				1
 85			end
 86
 87			def to_i; end
 88
 89			def as_json(*)
 90				nil
 91			end
 92		end
 93	end
 94
 95	value_semantics do
 96		uri Either(/:/, NilClass)
 97		def_attr :timeout, Timeout, coerce: Timeout.method(:for)
 98	end
 99
100	def with(new_attrs)
101		CustomerFwd.for(to_h.merge(new_attrs))
102	end
103
104	def voicemail_enabled?
105		!timeout.infinite?
106	end
107
108	def create_call(account)
109		raise InfiniteTimeout, self if timeout.infinite?
110
111		request = Bandwidth::ApiCreateCallRequest.new.tap { |cc|
112			cc.to = to
113			cc.call_timeout = timeout.to_i
114			yield cc if block_given?
115		}
116		BANDWIDTH_VOICE.create_call(account, body: request).data.call_id
117	end
118
119	def as_json(*)
120		[to_h]
121	end
122
123	def to_json(*args)
124		as_json.to_json(*args)
125	end
126
127	class Tel < CustomerFwd
128		def initialize(values)
129			super
130			raise "Bad tel format: #{uri}" unless uri.match?(/\Atel:\+1\d{10}\Z/)
131		end
132
133		def to
134			uri.sub(/^tel:/, "")
135		end
136	end
137
138	class SIP < CustomerFwd
139		def to
140			uri
141		end
142	end
143
144	class XMPP < CustomerFwd
145		def to
146			jid = uri.sub(/^xmpp:/, "")
147			"sip:#{ERB::Util.url_encode(jid)}@sip.cheogram.com"
148		end
149	end
150
151	class None < CustomerFwd
152		def create_call(*); end
153
154		def to; end
155
156		def as_json(*); end
157	end
158
159	URIS = {
160		tel: Tel,
161		sip: SIP,
162		xmpp: XMPP
163	}.freeze
164end