# frozen_string_literal: true

require "test_helper"
require "bwmsgsv2_repo"
require "backend_sgx"
require "trivial_backend_sgx_repo"
require "customer"

BackendSgx::IQ_MANAGER = Minitest::Mock.new
IBRRepo::IQ_MANAGER = Minitest::Mock.new

class BackendSgxTest < Minitest::Test
	def test_registered
		IBRRepo::IQ_MANAGER.expect(
			:write,
			EMPromise.resolve(Blather::Stanza::Iq::IBR.new.tap { |ibr|
				ibr.registered = true
			}),
			[Matching.new do |ibr|
				assert_equal :get, ibr.type
				assert_equal "customer_test@component", ibr.from.to_s
			end]
		)
		sgx = Bwmsgsv2Repo.new(redis: FakeRedis.new).get("test").sync
		assert sgx.registered?
	end
	em :test_registered

	def test_registered_not_registered
		IBRRepo::IQ_MANAGER.expect(
			:write,
			EMPromise.resolve(Blather::Stanza::Iq::IBR.new.tap { |ibr|
				ibr.registered = false
			}),
			[Matching.new do |ibr|
				assert_equal :get, ibr.type
				assert_equal "customer_test@component", ibr.from.to_s
			end]
		)
		sgx = Bwmsgsv2Repo.new(redis: FakeRedis.new).get("test").sync
		refute sgx.registered?
	end
	em :test_registered_not_registered

	def test_register!
		BackendSgx::IQ_MANAGER.expect(
			:write,
			EMPromise.resolve(OpenStruct.new(error?: false)),
			[Matching.new do |ibr|
				assert_equal "customer_test@component", ibr.from.to_s
				assert_equal "test_bw_account", ibr.nick
				assert_equal "test_bw_user", ibr.username
				assert_equal "test_bw_password", ibr.password
				assert_equal "+15555550000", ibr.phone
			end]
		)
		sgx = TrivialBackendSgxRepo.new(redis: FakeRedis.new).get("test").sync
		sgx.register!("+15555550000")
		BackendSgx::IQ_MANAGER.verify
	end
	em :test_register!

	def test_set_port_out_pin_happy_path
		sgx = TrivialBackendSgxRepo.new(redis: FakeRedis.new).get("test").sync
		cust = customer("test", sgx: sgx)

		port_out_pin = "74hwsn"
		session_id = "session_yay_awesome"

		BackendSgx::IQ_MANAGER.expect(
			:write,
			EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
				iq.command[:sessionid] = session_id
			}),
			[Matching.new do |iq|
				assert_equal CONFIG[:sgx], iq.to.to_s
				assert_equal "customer_test@component", iq.from.to_s
				assert_equal "set-port-out-pin", iq.node
				assert_equal :execute, iq.action
			end]
		)

		BackendSgx::IQ_MANAGER.expect(
			:write,
			EMPromise.resolve(OpenStruct.new(
				status: :completed,
				note_type: :info
			)),
			[Matching.new do |iq|
				assert_equal :complete, iq.action
				assert_equal :submit, iq.form.type
				assert_equal CONFIG[:sgx], iq.to.to_s
				assert_equal "customer_test@component", iq.from.to_s
				assert_equal "set-port-out-pin", iq.node
				assert_equal session_id, iq.sessionid

				pin_field = iq.form.fields.find { |f| f.var == "pin" }
				assert_equal port_out_pin, pin_field.value
				assert_equal "text-private", pin_field.type

				confirm_field = iq.form.fields.find { |f| f.var == "confirm_pin" }
				assert_equal port_out_pin, confirm_field.value
				assert_equal "text-private", confirm_field.type
			end]
		)

		result = sgx.set_port_out_pin(cust, port_out_pin).sync
		assert_nil result
		assert_mock BackendSgx::IQ_MANAGER
	end
	em :test_set_port_out_pin_happy_path

	def test_set_port_out_pin_validation
		sgx = TrivialBackendSgxRepo.new(redis: FakeRedis.new).get("test").sync
		cust = customer("test", sgx: sgx)

		[
			["123", "PIN must be 4-10 alphanumeric characters"],
			["12345678901", "PIN must be 4-10 alphanumeric characters"],
			["123!", "PIN must be 4-10 alphanumeric characters"],
			["pin with spaces", "PIN must be 4-10 alphanumeric characters"],
			["", "PIN must be 4-10 alphanumeric characters"]
		].each do |invalid_pin, expected_error|
			session_id = "session_validation_#{invalid_pin.gsub(/[^a-zA-Z0-9]/, '')}"

			BackendSgx::IQ_MANAGER.expect(
				:write,
				EMPromise.resolve(Blather::Stanza::Iq::Command.new.tap { |iq|
					iq.command[:sessionid] = session_id
				}),
				[Matching.new do |iq|
					assert_equal CONFIG[:sgx], iq.to.to_s
					assert_equal "customer_test@component", iq.from.to_s
					assert_equal "set-port-out-pin", iq.node
					assert_equal :execute, iq.action
				end]
			)

			note = Struct.new(:text) do
				def [](key)
					"error" if key == "type"
				end
			end.new(expected_error)

			BackendSgx::IQ_MANAGER.expect(
				:write,
				EMPromise.resolve(OpenStruct.new(
					status: :completed,
					note: note
				)),
				[Matching.new do |iq|
					assert_equal :complete, iq.action
					assert_equal :submit, iq.form.type
					assert_equal CONFIG[:sgx], iq.to.to_s
					assert_equal "customer_test@component", iq.from.to_s
					assert_equal "set-port-out-pin", iq.node
					assert_equal session_id, iq.sessionid

					pin_field = iq.form.fields.find { |f| f.var == "pin" }
					assert_equal invalid_pin, pin_field.value
					assert_equal "text-private", pin_field.type

					confirm_field = iq.form.fields.find { |f| f.var == "confirm_pin" }
					assert_equal invalid_pin, confirm_field.value
					assert_equal "text-private", confirm_field.type
				end]
			)

			error = assert_raises(RuntimeError) {
				sgx.set_port_out_pin(cust, invalid_pin).sync
			}

			assert_equal expected_error, error.message
		end

		assert_mock BackendSgx::IQ_MANAGER
	end
	em :test_set_port_out_pin_validation
end
