//
// Copyright © 2023 Nevis Security AG. All rights reserved.
//

import NevisMobileAuthentication

typealias OOBRegistrationHandler = (OutOfBandRegistration) -> ()
typealias OOBAuthenticationHandler = (OutOfBandAuthentication) -> ()

struct OutOfBandOperationMethodHandler: MethodHandler {
	func execute(using client: MobileAuthenticationClient, with message: ChannelInMessage) {
		let message: OutOfBandOperationMessage = validate(message: message)
		let operation = OutOfBandOperation(operationId: message.operationId)
		OperationCache.shared.put(operation, using: message.operationId)

		client.operations.outOfBandOperation
			.configure(by: message,
			           operation: operation,
			           onRegistration: register(using: message.operationId, subOperationId: message.subOperationId),
			           onAuthentication: authenticate(using: message.operationId, subOperationId: message.subOperationId))
			.execute()
	}
}

private extension OutOfBandOperationMethodHandler {
	func register(using operationId: String, subOperationId: String) -> OOBRegistrationHandler {
		{ registration in
			OperationCache.shared.delete(by: operationId)

			let operation = OutOfBandRegistrationOperation(operationId: subOperationId,
			                                               registration: registration)
			OperationCache.shared.put(operation, using: subOperationId)

			let message = OperationTypeMessage(operationId: operationId, operationType: .registration)
			MethodChannelHandler.shared.resolve(method: .oobOperation, message: message)
		}
	}

	func authenticate(using operationId: String, subOperationId: String) -> OOBAuthenticationHandler {
		{ authentication in
			OperationCache.shared.delete(by: operationId)

			let operation = OutOfBandAuthenticationOperation(operationId: subOperationId,
			                                                 authentication: authentication)
			OperationCache.shared.put(operation, using: subOperationId)

			let message = OperationTypeMessage(operationId: operationId, operationType: .authentication)
			MethodChannelHandler.shared.resolve(method: .oobOperation, message: message)
		}
	}
}
