import { useCallback, useEffect, useState, useRef } from "react";
import { UnresponsiveDeviceError, UserRefusedAllowManager } from "@ledgerhq/errors";
import { getGenuineCheckFromDeviceId as defaultGetGenuineCheckFromDeviceId } from "../getGenuineCheckFromDeviceId";
import { isDmkError } from "../../deviceSDK/tasks/core";
const SOCKET_EVENT_PAYLOAD_GENUINE = "0000";
const clearTimeoutRef = (timeoutRef) => {
    if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
        timeoutRef.current = null;
    }
};
const isDmkDeviceDisconnectedError = (e) => isDmkError(e) && e._tag === "DeviceDisconnectedWhileSendingError";
/**
 * Hook to check that a device is genuine
 * It replaces a DeviceAction if we're only interested in getting the genuine check
 * @param getGenuineCheckFromDeviceId An optional function to get a genuine check for a given device id,
 * by default set to live-common/hw/getGenuineCheckFromDeviceId.
 * This dependency injection is needed for LLD to have the hook working on the internal thread
 * @param isHookEnabled A boolean to enable (true, default value) or disable (false) the hook
 * @param deviceId A device id, or an empty string if device is usb plugged
 * @param lockedDeviceTimeoutMs Time of no response from device after which the device is considered locked, in ms. Default 1000ms.
 * @param permissionTimeoutMs Time to wait for a device response to a permission request, in ms. Default 60s.
 * @returns An object containing:
 * - genuineState: the current GenuineState
 * - devicePermissionState: the current DevicePermissionState
 * - error: any error that occurred during the genuine check, or null
 */
export const useGenuineCheck = ({ getGenuineCheckFromDeviceId = defaultGetGenuineCheckFromDeviceId, isHookEnabled = true, deviceId, deviceName, lockedDeviceTimeoutMs = 1000, permissionTimeoutMs = 60 * 1000, }) => {
    const [genuineState, setGenuineState] = useState("unchecked");
    const [devicePermissionState, setDevicePermissionState] = useState("unrequested");
    const [error, setError] = useState(null);
    const timeoutRef = useRef(null);
    const resetGenuineCheckState = useCallback(() => {
        setDevicePermissionState("unrequested");
        setGenuineState("unchecked");
        setError(null);
    }, []);
    useEffect(() => {
        if (!isHookEnabled) {
            return;
        }
        const sub = getGenuineCheckFromDeviceId({
            deviceId,
            deviceName,
            lockedDeviceTimeoutMs,
        }).subscribe({
            next: ({ socketEvent, lockedDevice }) => {
                if (socketEvent) {
                    switch (socketEvent.type) {
                        case "device-permission-requested":
                            setDevicePermissionState("requested");
                            timeoutRef.current = setTimeout(() => {
                                setError(new UnresponsiveDeviceError());
                                clearTimeoutRef(timeoutRef);
                            }, permissionTimeoutMs);
                            break;
                        case "device-permission-granted":
                            clearTimeoutRef(timeoutRef);
                            setDevicePermissionState("granted");
                            break;
                        case "result":
                            clearTimeoutRef(timeoutRef);
                            if (socketEvent.payload === SOCKET_EVENT_PAYLOAD_GENUINE) {
                                setGenuineState("genuine");
                            }
                            else {
                                setGenuineState("non-genuine");
                            }
                            break;
                    }
                }
                else {
                    clearTimeoutRef(timeoutRef);
                    // If no socketEvent, the device is locked or has been unlocked
                    if (lockedDevice) {
                        setDevicePermissionState("unlock-needed");
                    }
                    else {
                        setDevicePermissionState("unlocked");
                    }
                }
            },
            error: (e) => {
                clearTimeoutRef(timeoutRef);
                if (e instanceof UserRefusedAllowManager) {
                    setDevicePermissionState("refused");
                }
                else if (e instanceof Error || isDmkDeviceDisconnectedError(e)) {
                    // Probably an error of type DisconnectedDeviceDuringOperation or something else
                    setError(e);
                }
                else {
                    setError(new Error(`Unknown error: ${e}`));
                }
            },
        });
        return () => {
            sub.unsubscribe();
        };
    }, [
        isHookEnabled,
        deviceId,
        deviceName,
        lockedDeviceTimeoutMs,
        getGenuineCheckFromDeviceId,
        permissionTimeoutMs,
    ]);
    return {
        genuineState,
        devicePermissionState,
        error,
        resetGenuineCheckState,
    };
};
//# sourceMappingURL=useGenuineCheck.js.map