# frozen_string_literal: true

require "test_helper"
require "admin_command"

BackendSgx::IQ_MANAGER = Minitest::Mock.new
AdminAction::LaunchSnikket::IQ_MANAGER = Minitest::Mock.new
Customer::BLATHER = Minitest::Mock.new
AdminActionRepo::REDIS = Minitest::Mock.new
TrivialBackendSgxRepo::REDIS = Minitest::Mock.new

class AdminCommandTest < Minitest::Test
	def admin_command(tel="+15556667777")
		sgx = Minitest::Mock.new(OpenStruct.new(
			registered?: OpenStruct.new(phone: tel)
		))
		[
			sgx,
			AdminCommand.new(
				customer(sgx: sgx),
				CustomerRepo.new(db: FakeDB.new),
				AdminActionRepo.new,
				Snikket::Repo.new(db: FakeDB.new)
			)
		]
	end

	def test_no_user
		q_form = Blather::Stanza::Iq::Command.new
		q_form.action = :complete
		q_form.form.fields = [
			{ var: "q", value: "testuser" }
		]

		customer_repo = Minitest::Mock.new

		result = execute_command {
			customer_repo.expect(
				:find_by_format,
				EMPromise.resolve(OpenStruct.new(
					customer_id: "testuser",
					billing_customer_id: "testuser",
					balance: 0.to_d,
					jid: Blather::JID.new("test@example.com"),
					tndetails: {}
				)),
				["testuser"]
			)

			customer_repo.expect(
				:find_by_format,
				EMPromise.resolve(nil),
				[Blather::JID]
			)

			customer_repo.expect(
				:find_by_format,
				EMPromise.resolve(nil),
				[ProxiedJID]
			)

			TrivialBackendSgxRepo::REDIS.expect(
				:get,
				EMPromise.resolve(nil),
				["jmp_customer_backend_sgx-testuser"]
			)

			TrustLevelRepo::REDIS.expect(
				:get,
				EMPromise.resolve("Customer"),
				["jmp_customer_trust_level-testuser"]
			)

			TrustLevelRepo::DB.expect(
				:query_one,
				EMPromise.resolve({ settled_amount: 0 }),
				[String, "testuser"], default: {}
			)

			Subaccount::DB.expect(
				:query_defer,
				EMPromise.resolve([]),
				[String, ["testuser"]]
			)

			Command::COMMAND_MANAGER.expect(
				:write,
				EMPromise.resolve(q_form),
				[Matching.new do |iq|
					 assert_equal :form, iq.form.type
					 assert iq.form.field("q")
				 end]
			)

			AdminCommand.for(nil, customer_repo).start.catch { |e| e }
		}

		assert result.stanza.completed?
		assert_mock customer_repo
		assert_mock Command::COMMAND_MANAGER
		assert_mock TrustLevelRepo::REDIS
		assert_mock Subaccount::DB
		assert_mock TrivialBackendSgxRepo::REDIS
	end
	em :test_no_user

	def test_action_launch_snikket
		sgx, admin = admin_command
		domain_form = Blather::Stanza::Iq::Command.new
		domain_form.form.fields = [
			{ var: "domain", value: "test.snikket.chat" }
		]

		launched = Snikket::Launched.new
		launched << Niceogiri::XML::Node.new(
			:launched, launched.document, "xmpp:snikket.org/hosting/v1"
		).tap { |inner|
			inner << Niceogiri::XML::Node.new(
				:'instance-id', launched.document, "xmpp:snikket.org/hosting/v1"
			).tap { |id|
				id.content = "si-1234"
			}
			inner << Niceogiri::XML::Node.new(
				:bootstrap, launched.document, "xmpp:snikket.org/hosting/v1"
			).tap { |bootstrap|
				bootstrap << Niceogiri::XML::Node.new(
					:token, launched.document, "xmpp:snikket.org/hosting/v1"
				).tap { |token|
					token.content = "TOKEN"
				}
			}
		}

		result = execute_command {
			Command::COMMAND_MANAGER.expect(
				:write,
				EMPromise.resolve(domain_form),
				[Matching.new do |iq|
					 assert_equal :form, iq.form.type
					 assert iq.form.field("domain")
				 end]
			)
			Command::COMMAND_MANAGER.expect(
				:write,
				EMPromise.reject(:test_result),
				[Matching.new do |iq|
					 assert :result, iq.type
					 assert(
						 "https://test.snikket.chat/invites_bootstrap?token=TOKEN",
						 iq.form.field("bootstrap-uri").value
					 )
				 end]
			)

			AdminAction::LaunchSnikket::IQ_MANAGER.expect(
				:write,
				EMPromise.resolve(launched),
				[Matching.new do |iq|
					 assert_equal :set, iq.type
					 assert_equal CONFIG[:snikket_hosting_api], iq.to.to_s
					 assert_equal(
						 "test.snikket.chat",
						 iq.xpath(
							 "./ns:launch/ns:domain",
							 ns: "xmpp:snikket.org/hosting/v1"
						 ).text
					 )
				 end]
			)

			admin.action_launch_snikket.catch { |e| e }
		}

		assert_equal :test_result, result
		assert_mock sgx
		assert_mock AdminAction::LaunchSnikket::IQ_MANAGER
		assert_mock Customer::BLATHER
	end
	em :test_action_launch_snikket

	def test_action_cancel_account
		req = stub_request(:post, "https://api.churnbuster.io/v1/cancellations")
			.with(
				body: {
					customer: {
						source: "braintree",
						source_id: "test",
						email: "test@smtp.cheogram.com",
						properties: {}
					},
					subscription: {
						source: "braintree",
						source_id: "test"
					}
				}.to_json
			)
			.to_return(status: 200, body: "", headers: {})

		sgx, admin = admin_command

		Customer::BLATHER.expect(
			:<<,
			EMPromise.resolve(nil),
			[
				Matching.new do |m|
					assert_equal "Your JMP account has been cancelled.", m.body
					assert_equal "test@example.net", m.to.to_s
					assert_equal "notify_from@component", m.from.to_s
				end
			]
		)

		Customer::BLATHER.expect(
			:<<,
			EMPromise.resolve(nil),
			[
				Matching.new do |iq|
					assert iq.remove?
					assert_equal "test@example.net", iq.to.to_s
					assert_equal "component", iq.from.to_s
				end
			]
		)

		sgx.expect(:deregister!, EMPromise.resolve(nil))

		stub_request(
			:post,
			"https://dashboard.bandwidth.com/v1.0/accounts//disconnects"
		).with(
			body: {
				name: "test",
				DisconnectTelephoneNumberOrderType: {
					TelephoneNumberList: {
						TelephoneNumber: "5556667777"
					}
				}
			}.to_xml(indent: 0, root: "DisconnectTelephoneNumberOrder")
		).to_return(status: 200, body: "")

		admin.action_cancel_account.sync

		assert_mock sgx
		assert_mock BackendSgx::IQ_MANAGER
		assert_mock Customer::BLATHER
		assert_requested req
	end
	em :test_action_cancel_account

	def test_action_cancel_account_keep_number
		req = stub_request(:post, "https://api.churnbuster.io/v1/cancellations")
			.with(
				body: {
					customer: {
						source: "braintree",
						source_id: "test",
						email: "test@smtp.cheogram.com",
						properties: {}
					},
					subscription: {
						source: "braintree",
						source_id: "test"
					}
				}.to_json
			)
			.to_return(status: 200, body: "", headers: {})

		sgx, admin = admin_command("+15566667777")

		Customer::BLATHER.expect(
			:<<,
			EMPromise.resolve(nil),
			[
				Matching.new do |m|
					assert_equal "Your JMP account has been cancelled.", m.body
					assert_equal "test@example.net", m.to.to_s
					assert_equal "notify_from@component", m.from.to_s
				end
			]
		)

		Customer::BLATHER.expect(
			:<<,
			EMPromise.resolve(nil),
			[
				Matching.new do |iq|
					assert iq.remove?
					assert_equal "test@example.net", iq.to.to_s
					assert_equal "component", iq.from.to_s
				end
			]
		)

		sgx.expect(:deregister!, EMPromise.resolve(nil))

		stub_request(
			:post,
			"https://dashboard.bandwidth.com/v1.0/accounts/moveto/moveTns"
		).with(
			body: {
				CustomerOrderId: "test",
				SourceAccountId: "test_bw_account",
				SiteId: "movetosite",
				SipPeerId: "movetopeer",
				TelephoneNumbers: { TelephoneNumber: "5566667777" }
			}.to_xml(indent: 0, root: "MoveTnsOrder")
		).to_return(status: 200, body: "")

		admin.action_cancel_account.sync

		assert_mock sgx
		assert_mock BackendSgx::IQ_MANAGER
		assert_mock Customer::BLATHER
		assert_requested req
	end
	em :test_action_cancel_account_keep_number
end
