import { interval, of } from "rxjs";
import { debounce, scan, tap } from "rxjs/operators";
import { useEffect, useCallback, useState } from "react";
import { log } from "@ledgerhq/logs";
import { useReplaySubject } from "../../observable";
import { currentMode } from "./app";
import { getImplementation } from "./implementations";
import { getLatestFirmwareForDeviceUseCase } from "../../device/use-cases/getLatestFirmwareForDeviceUseCase";
const mapResult = ({ deviceInfo, device, result }) => deviceInfo && device
    ? {
        device,
        deviceInfo,
        result,
    }
    : null;
const getInitialState = (device) => ({
    isLoading: device === undefined || !!device,
    requestQuitApp: false,
    unresponsive: false,
    isLocked: false,
    allowManagerRequested: false,
    allowManagerGranted: false,
    device,
    deviceInfo: null,
    deviceId: null,
    result: null,
    error: null,
});
const reducer = (state, e) => {
    switch (e.type) {
        case "unresponsiveDevice":
            return { ...state, unresponsive: true };
        case "lockedDevice":
            return { ...state, isLocked: true };
        case "deviceChange":
            return getInitialState(e.device);
        case "error":
            return {
                ...getInitialState(state.device),
                error: e.error,
                isLoading: false,
                isLocked: false,
            };
        case "appDetected":
            return {
                ...state,
                unresponsive: false,
                isLocked: false,
                requestQuitApp: true,
            };
        case "osu":
        case "bootloader":
            return {
                ...state,
                isLoading: false,
                unresponsive: false,
                isLocked: false,
                requestQuitApp: false,
                deviceInfo: e.deviceInfo,
            };
        case "listingApps":
            return {
                ...state,
                isLoading: true,
                requestQuitApp: false,
                unresponsive: false,
                isLocked: false,
                deviceInfo: e.deviceInfo,
            };
        case "device-permission-requested":
            return {
                ...state,
                unresponsive: false,
                isLocked: false,
                allowManagerRequested: true,
            };
        case "device-permission-granted":
            return {
                ...state,
                unresponsive: false,
                isLocked: false,
                allowManagerRequested: false,
                allowManagerGranted: true,
            };
        case "device-id":
            return {
                ...state,
                deviceId: e.deviceId,
            };
        case "result":
            return {
                ...state,
                isLoading: false,
                unresponsive: false,
                isLocked: false,
                result: e.result,
            };
    }
    return state;
};
export const createAction = (task) => {
    const useHook = (device, request = {}) => {
        const [state, setState] = useState(() => getInitialState());
        const [resetIndex, setResetIndex] = useState(0);
        const deviceSubject = useReplaySubject(device);
        // repair modal will interrupt everything and be rendered instead of the background content
        const [repairModalOpened, setRepairModalOpened] = useState(null);
        useEffect(() => {
            if (request?.cancelExecution)
                return;
            const impl = getImplementation(currentMode)({
                deviceSubject,
                task,
                request,
                retryableWithDelayDisconnectedErrors: [],
            });
            if (repairModalOpened)
                return;
            const sub = impl
                .pipe(tap((e) => log("actions-manager-event", e.type, e)), debounce((e) => ("replaceable" in e && e.replaceable ? interval(100) : of(null))), scan(reducer, getInitialState()))
                .subscribe(setState);
            return () => {
                sub.unsubscribe();
            };
        }, [deviceSubject, resetIndex, repairModalOpened, request]);
        const { deviceInfo } = state;
        useEffect(() => {
            if (!deviceInfo)
                return;
            // Preload latest firmware in parallel
            getLatestFirmwareForDeviceUseCase(deviceInfo).catch((e) => {
                log("warn", e.message);
            });
        }, [deviceInfo]);
        const onRepairModal = useCallback(open => {
            setRepairModalOpened(open
                ? {
                    auto: false,
                }
                : null);
        }, []);
        const closeRepairModal = useCallback(() => {
            // Sets isBootloader to true to avoid having the renderBootloaderStep rendered,
            // on which the user could re-trigger a bootloader repairing scenario that is not needed
            setState(prevState => {
                return {
                    ...prevState,
                    deviceInfo: prevState.deviceInfo
                        ? { ...prevState.deviceInfo, isBootloader: false }
                        : null,
                };
            });
            setRepairModalOpened(null);
        }, []);
        const onRetry = useCallback(() => {
            setResetIndex(currIndex => currIndex + 1);
            setState(s => getInitialState(s.device));
        }, []);
        const onAutoRepair = useCallback(() => {
            setRepairModalOpened({
                auto: true,
            });
        }, []);
        return {
            ...state,
            repairModalOpened,
            onRetry,
            onAutoRepair,
            closeRepairModal,
            onRepairModal,
        };
    };
    return {
        useHook,
        mapResult,
    };
};
//# sourceMappingURL=manager.js.map