"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDeviceInfoTask = exports.parseDeviceInfo = exports.internalGetDeviceInfoTask = void 0;
const errors_1 = require("@ledgerhq/errors");
const logs_1 = require("@ledgerhq/logs");
const getVersion_1 = require("../commands/getVersion");
const isDevFirmware_1 = __importDefault(require("../../hw/isDevFirmware"));
const provider_1 = require("../../manager/provider");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const core_1 = require("./core");
const quitApp_1 = require("../commands/quitApp");
const core_2 = require("../transports/core");
const device_management_kit_1 = require("@ledgerhq/device-management-kit");
const ManagerAllowedFlag = 0x08;
const PinValidatedFlag = 0x80;
// Exported for tests
function internalGetDeviceInfoTask({ deviceId, deviceName, }) {
    return new rxjs_1.Observable(subscriber => {
        return ((0, core_2.withTransport)(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(({ transportRef }) => (0, quitApp_1.quitApp)(transportRef.current).pipe((0, operators_1.switchMap)(() => {
            return (0, core_1.retryOnErrorsCommandWrapper)({
                command: getVersion_1.getVersion,
                allowedErrors: [{ maxRetries: 3, errorClass: errors_1.DisconnectedDevice }],
                allowedDmkErrors: [new device_management_kit_1.SendApduEmptyResponseError()],
            })(transportRef, {});
        }), (0, operators_1.map)(value => {
            if (value.type === "unresponsive") {
                return {
                    type: "error",
                    error: new errors_1.UnresponsiveDeviceError(),
                    retrying: true,
                };
            }
            const { firmwareInfo } = value;
            const deviceInfo = (0, exports.parseDeviceInfo)(firmwareInfo);
            return { type: "data", deviceInfo };
        })))
            // Any error will be handled by the sharedLogicTaskWrapper, which will map it a relevant event
            .subscribe(subscriber));
    });
}
exports.internalGetDeviceInfoTask = internalGetDeviceInfoTask;
const parseDeviceInfo = (firmwareInfo) => {
    const { isBootloader, rawVersion, targetId, seVersion, seTargetId, mcuBlVersion, mcuVersion, mcuTargetId, flags, bootloaderVersion, hardwareVersion, languageId, charonState, } = firmwareInfo;
    const isOSU = rawVersion.includes("-osu");
    const version = rawVersion.replace("-osu", "");
    const m = rawVersion.match(/([0-9]+.[0-9]+(.[0-9]+){0,1})?(-(.*))?/);
    const [, majMin, , , postDash] = m || [];
    const providerName = provider_1.PROVIDERS[postDash] ? postDash : null;
    const flag = flags.length > 0 ? flags[0] : 0;
    const managerAllowed = !!(flag & ManagerAllowedFlag);
    const pinValidated = !!(flag & PinValidatedFlag);
    let isRecoveryMode = false;
    let onboarded = true;
    if (flags.length === 4) {
        // Nb Since LNS+ unseeded devices are visible + extra flags
        isRecoveryMode = !!(flags[0] & 0x01);
        onboarded = !!(flags[0] & 0x04);
    }
    (0, logs_1.log)("hw", "deviceInfo: se@" +
        version +
        " mcu@" +
        mcuVersion +
        (isOSU ? " (osu)" : isBootloader ? " (bootloader)" : ""));
    const hasDevFirmware = (0, isDevFirmware_1.default)(seVersion);
    const deviceInfo = {
        version,
        mcuVersion,
        seVersion,
        mcuBlVersion,
        majMin,
        providerName: providerName || null,
        targetId,
        hasDevFirmware,
        seTargetId,
        mcuTargetId,
        isOSU,
        isBootloader,
        isRecoveryMode,
        managerAllowed,
        pinValidated,
        onboarded,
        bootloaderVersion,
        hardwareVersion,
        languageId,
        seFlags: flags,
        charonState: charonState,
    };
    return deviceInfo;
};
exports.parseDeviceInfo = parseDeviceInfo;
/**
 * Task to get the `DeviceInfo` of a device
 *
 * @param `deviceId` A device id, or an empty string if device is usb plugged
 * @returns An observable that emits `GetDeviceInfoTaskEvent` events
 */
exports.getDeviceInfoTask = (0, core_1.sharedLogicTaskWrapper)(internalGetDeviceInfoTask);
//# sourceMappingURL=getDeviceInfo.js.map