/**
 * Copyright © 2024 Nevis Security AG. All rights reserved.
 */

import uuid from 'react-native-uuid';

import { DeviceInformationCheckResult } from './DeviceInformationCheckResult';
import { DeviceInformationCheckPlatformOperation } from '../../cache/operation/DeviceInformationCheckPlatformOperation';
import { PlatformOperationCache } from '../../cache/PlatformOperationCache';
import NevisMobileAuthenticationSdkReact from '../../MobileAuthenticationSdk';
import { DeviceInformationCheckResultMessage } from '../../model/messages/in/DeviceInformationCheckResultMessage';
import { DeviceInformationCheckMessage } from '../../model/messages/out/DeviceInformationCheckMessage';
import { HttpOperation, HttpOperationImpl } from '../HttpOperation';

/**
 * The operation retrieving the mismatches that exist between the configuration in the server and in
 * the mobile device application.
 *
 * The configuration mismatches can be fixed by providing them to the {@link DeviceInformationSync}
 * operation.
 *
 * This is supported only with FIDO UAF registrations made against a backend with nevisFIDO 7.2408.**
 * or later. With registrations made with earlier versions of nevisFIDO, this operation can return
 * {@link MissingAuthenticatorInServer} false positives, that is, it can report mismatches, when the
 * credentials of backend and server are in sync.
 *
 * Usage example:
 * ```ts
 *   [...]
 *   async retrieveDeviceInformationMismatches(
 *       operations: Operations
 *   ): Promise<void> {
 *       operations.deviceInformationCheck
 *           .onResult((result) => {
 *               // handle the retrieved mismatches. They can be fixed by
 *               // running a DeviceInformationSync operation.
 *           })
 *           .execute();
 *   }
 *   [...]
 * ```
 *
 * @see
 * - {@link DeviceInformationCheckResult}
 * - {@link DeviceInformationSync}
 * - {@link Operations.deviceInformationCheck}
 */
export abstract class DeviceInformationCheck extends HttpOperation<DeviceInformationCheck> {
	/**
	 * Specifies the object that will be invoked with the {@link DeviceInformationCheckResult}
	 * containing the configuration mismatches an errors (if any) that occurred.
	 *
	 * **IMPORTANT** \
	 * Providing the {@link onResult} callback is required.
	 *
	 * **WARNING** \
	 * The information returned in `DeviceInformationCheckResult` is only reliable for registrations
	 * done using the Authentication Mobile SDK 3.8.0 or later. If your application has been upgraded
	 * from previous versions of the SDK and thus some users were registered using earlier versions,
	 * some false positive {@link MissingAuthenticatorInServer} mismatches can be returned for those
	 * users.
	 *
	 * @param onResult the callback that will be invoked when the operation finishes.
	 * @return a {@link DeviceInformationCheck} object.
	 */
	abstract onResult(
		onResult: (result: DeviceInformationCheckResult) => void
	): DeviceInformationCheck;
}

export class DeviceInformationCheckImpl
	extends HttpOperationImpl<DeviceInformationCheck>
	implements DeviceInformationCheck
{
	private _onResult?: (result: DeviceInformationCheckResult) => void;

	constructor() {
		super();
	}

	onResult(onResult: (result: DeviceInformationCheckResult) => void): DeviceInformationCheck {
		this._onResult = onResult;
		return this;
	}

	async execute(): Promise<void> {
		const operationId = uuid.v4() as string;
		const operation = new DeviceInformationCheckPlatformOperation(operationId, this._onResult);

		PlatformOperationCache.getInstance().put(operation);

		const message = new DeviceInformationCheckMessage(
			operationId,
			this.onResult !== undefined,
			this.httpRequestHeaders
		);

		function finish() {
			PlatformOperationCache.getInstance().delete(operationId);
		}

		return NevisMobileAuthenticationSdkReact.deviceInformationCheck(message).then(
			(result: DeviceInformationCheckResultMessage) => {
				const resultMessage = DeviceInformationCheckResultMessage.fromJson(result);
				operation.handleResult(resultMessage.result);
				finish();
			}
		);
	}
}
