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

import NevisMobileAuthentication

final class PinPolicyImpl: PinPolicy, Codable, Sendable {
	// MARK: Properties

	let operationId: String
	let minLength: Int
	let maxLength: Int

	// MARK: Properties

	enum Constants {
		static let minLength = 6
		static let maxLength = 6
	}

	// MARK: Initialization

	init(operationId: String, minLength: Int = Constants.minLength, maxLength: Int = Constants.maxLength) {
		self.operationId = operationId
		self.minLength = minLength
		self.maxLength = maxLength
	}

	// MARK: PinPolicy

	func validatePinForEnrollment(_ pin: String,
	                              onSuccess: @escaping @Sendable () -> (),
	                              onError: @escaping @Sendable (PinEnrollmentValidationError) -> ())
	{
		Task {
			let operation: any UserInteractionOperation = await OperationCache.shared.read(by: operationId)
			let authenticator = await operation.findAuthenticator(aaid: AuthenticatorAaid.Pin)
			let state = PinValidateForEnrollmentState(authenticator: authenticator,
			                                          onSuccess: onSuccess,
			                                          onValidationError: onError)
			await OperationCache.shared.update(by: operationId,
			                                   operation: operation.update(state: state))

			let message = PinValidationMessage(operationId: operationId,
			                                   pin: pin)
			EventEmitter.shared.dispatch(event: .pinValidateForEnrollment, message: message)
		}
	}

	func validatePinForPinChange(_ pin: String,
	                             onSuccess: @escaping @Sendable () -> (),
	                             onError: @escaping @Sendable (PinChangeValidationError) -> ())
	{
		Task {
			let operation: PinChangeOperation = await OperationCache.shared.read(by: operationId)
			let state = PinValidateForPinChangeState(onSuccess: onSuccess,
			                                         onValidationError: onError)
			await OperationCache.shared.update(by: operationId,
			                                   operation: operation.update(state: state))

			let message = PinValidationMessage(operationId: operationId,
			                                   pin: pin)
			EventEmitter.shared.dispatch(event: .pinValidateForPinChange, message: message)
		}
	}
}
