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

import NevisMobileAuthentication

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

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

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

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

				let operation = OutOfBandRegistrationOperation(operationId: subOperationId,
				                                               method: ReactMethod(name: .oobRegister),
				                                               registration: registration)
				await OperationCache.shared.put(operation, using: subOperationId)

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

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

				let operation = OutOfBandAuthenticationOperation(operationId: subOperationId,
				                                                 method: ReactMethod(name: .oobAuthenticate),
				                                                 authentication: authentication)
				await OperationCache.shared.put(operation, using: subOperationId)

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