"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLatestAvailableFirmwareAction = exports.initialState = void 0;
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const getLatestFirmware_1 = require("../tasks/getLatestFirmware");
const getDeviceInfo_1 = require("../tasks/getDeviceInfo");
const core_1 = require("./core");
exports.initialState = {
    firmwareUpdateContext: null,
    deviceInfo: null,
    status: "idle",
    ...core_1.initialSharedActionState,
};
/**
 * Get the latest available firmware that the device could update to
 *
 * @param `deviceId` A device id, or an empty string if device is usb plugged
 * @returns an Observables that emits the evolution of the state machine until finding (or not)
 * the latest available firmware. The state is as follow (+ shared state with other actions):
 * - `firmwareUpdateContext`: the `FirmwareUpdateContext` when retrieved, null otherwise
 * - `deviceInfo`: the `DeviceInfo` when retrieved, null otherwise
 * - `status`: the current status of the action: "error" | "no-available-firmware" | "available-firmware" meaning the action has finished
 * - `error`: an error coming from the business logic, the device or internal. Some error are retried:
 *   `{ type`: "SharedError", retrying: true, ... }`
 * - `...sharedActionState`
 */
function getLatestAvailableFirmwareAction({ deviceId, deviceName, }) {
    const observable = new rxjs_1.Observable(subscriber => {
        subscriber.next({
            type: "stateUpdate",
            status: "ongoing",
        });
        (0, getDeviceInfo_1.getDeviceInfoTask)({ deviceId, deviceName })
            .pipe((0, operators_1.switchMap)(event => {
            if (event.type !== "data") {
                return (0, rxjs_1.of)(event);
            }
            const { deviceInfo } = event;
            // Update the action state before the next task
            subscriber.next({
                type: "stateUpdate",
                status: "ongoing",
                deviceInfo,
                lockedDevice: false,
                error: null,
            });
            // Keeps `deviceInfo` in the next event
            return (0, rxjs_1.forkJoin)([
                (0, getLatestFirmware_1.getLatestFirmwareTask)({ deviceId, deviceName, deviceInfo }),
                (0, rxjs_1.of)(deviceInfo),
            ]).pipe(
            // Creating a new "event"-like object, extending it with `deviceInfo`
            (0, operators_1.switchMap)(([event, deviceInfo]) => {
                return (0, rxjs_1.of)({
                    ...event,
                    deviceInfo,
                });
            }));
        }))
            .subscribe(subscriber);
    });
    return observable.pipe((0, operators_1.scan)((currentState, event) => {
        switch (event.type) {
            case "taskError":
                // Maps firmware already up-to-date task error to `status` "no-available-firmware"
                if (event.error === "FirmwareUpToDate") {
                    return {
                        ...currentState,
                        firmwareUpdateContext: null,
                        deviceInfo: "deviceInfo" in event ? event.deviceInfo : null,
                        status: "no-available-firmware",
                    };
                }
                return {
                    ...currentState,
                    error: {
                        type: "GetLatestAvailableFirmwareError",
                        name: event.error,
                    },
                    firmwareUpdateContext: null,
                    deviceInfo: "deviceInfo" in event ? event.deviceInfo : null,
                    status: "error",
                };
            case "data":
                return {
                    ...currentState,
                    error: null,
                    firmwareUpdateContext: event.firmwareUpdateContext,
                    deviceInfo: event.deviceInfo,
                    status: "available-firmware",
                };
            case "error": {
                const sharedState = (0, core_1.sharedReducer)({
                    event,
                });
                return {
                    ...currentState,
                    ...sharedState,
                    firmwareUpdateContext: null,
                    deviceInfo: "deviceInfo" in event ? event.deviceInfo : null,
                    status: sharedState.error?.retrying ? "ongoing" : "error",
                };
            }
            case "stateUpdate":
                // Updates only the prop that are defined in the event
                return {
                    ...currentState,
                    ...(event.lockedDevice !== undefined ? { lockedDevice: event.lockedDevice } : {}),
                    ...(event.deviceInfo !== undefined ? { deviceInfo: event.deviceInfo } : {}),
                    ...(event.status !== undefined ? { status: event.status } : {}),
                    ...(event.error !== undefined ? { error: event.error } : {}),
                };
        }
    }, exports.initialState));
}
exports.getLatestAvailableFirmwareAction = getLatestAvailableFirmwareAction;
//# sourceMappingURL=getLatestAvailableFirmware.js.map