"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const errors_1 = require("@ledgerhq/errors");
const device_core_1 = require("@ledgerhq/device-core");
const devices_1 = require("@ledgerhq/devices");
const live_dmk_shared_1 = require("@ledgerhq/live-dmk-shared");
const listAppsUseCase_1 = require("../device/use-cases/listAppsUseCase");
const deviceAccess_1 = require("./deviceAccess");
const getDeviceInfo_1 = __importDefault(require("./getDeviceInfo"));
const getAppAndVersion_1 = __importDefault(require("./getAppAndVersion"));
const isDashboardName_1 = require("./isDashboardName");
const errors_2 = require("../errors");
const attemptToQuitApp_1 = __importDefault(require("./attemptToQuitApp"));
const connectManagerEventMapper_1 = require("./connectManagerEventMapper");
const extractOnboardingState_1 = require("./extractOnboardingState");
const cmd = (transport, { request }) => new rxjs_1.Observable(o => {
    const timeoutSub = (0, rxjs_1.of)({
        type: "unresponsiveDevice",
    })
        .pipe((0, operators_1.delay)(1000))
        .subscribe(e => o.next(e));
    const sub = (0, rxjs_1.from)((0, getDeviceInfo_1.default)(transport))
        .pipe((0, operators_1.concatMap)(deviceInfo => {
        timeoutSub.unsubscribe();
        if (!deviceInfo.onboarded && !deviceInfo.isRecoveryMode) {
            throw new errors_2.DeviceNotOnboarded();
        }
        if (deviceInfo.isBootloader) {
            return (0, rxjs_1.of)({
                type: "bootloader",
                deviceInfo,
            });
        }
        if (deviceInfo.isOSU) {
            return (0, rxjs_1.of)({
                type: "osu",
                deviceInfo,
            });
        }
        if ((0, device_core_1.isCharonSupported)(deviceInfo.seVersion ?? "", (0, devices_1.identifyTargetId)(deviceInfo.seTargetId ?? 0)?.id)) {
            const onboardingState = (0, extractOnboardingState_1.extractOnboardingState)(deviceInfo.seFlags, deviceInfo.charonState);
            if (onboardingState.currentOnboardingStep === extractOnboardingState_1.OnboardingStep.BackupCharon) {
                throw new errors_2.DeviceNotOnboarded();
            }
        }
        return (0, rxjs_1.concat)((0, rxjs_1.of)({
            type: "listingApps",
            deviceInfo,
        }), (0, listAppsUseCase_1.listAppsUseCase)(transport, deviceInfo));
    }), (0, operators_1.catchError)((e) => {
        if (e instanceof errors_1.LockedDeviceError) {
            return (0, rxjs_1.of)({
                type: "lockedDevice",
            });
        }
        else if (e instanceof errors_1.DeviceOnDashboardExpected ||
            (e &&
                e instanceof errors_1.TransportStatusError &&
                [
                    errors_1.StatusCodes.CLA_NOT_SUPPORTED,
                    errors_1.StatusCodes.INS_NOT_SUPPORTED,
                    errors_1.StatusCodes.UNKNOWN_APDU,
                    0x6e01,
                    0x6d01, // No StatusCodes definition
                ].includes(e.statusCode))) {
            return (0, rxjs_1.from)((0, getAppAndVersion_1.default)(transport)).pipe((0, operators_1.concatMap)(appAndVersion => {
                return !request?.autoQuitAppDisabled && !(0, isDashboardName_1.isDashboardName)(appAndVersion.name)
                    ? (0, attemptToQuitApp_1.default)(transport, appAndVersion)
                    : (0, rxjs_1.of)({
                        type: "appDetected",
                    });
            }));
        }
        return (0, rxjs_1.throwError)(() => e);
    }))
        .subscribe(o);
    return () => {
        timeoutSub.unsubscribe();
        sub.unsubscribe();
    };
});
const isDmkTransport = (transport) => {
    return ("dmk" in transport &&
        transport.dmk !== undefined &&
        "sessionId" in transport &&
        transport.sessionId !== undefined);
};
function connectManagerFactory({ isLdmkConnectAppEnabled, } = { isLdmkConnectAppEnabled: false }) {
    if (!isLdmkConnectAppEnabled) {
        return ({ deviceId, deviceName, request }) => (0, deviceAccess_1.withDevice)(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(transport => cmd(transport, { deviceId, deviceName, request }));
    }
    return ({ deviceId, deviceName, request }) => (0, deviceAccess_1.withDevice)(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(transport => {
        if (!isDmkTransport(transport)) {
            return cmd(transport, { deviceId, deviceName, request });
        }
        const { dmk, sessionId } = transport;
        const deviceAction = new live_dmk_shared_1.PrepareConnectManagerDeviceAction({
            input: {
                unlockTimeout: 0, // Expect to fail immediately when device is locked
            },
        });
        const observable = dmk.executeDeviceAction({
            sessionId,
            deviceAction,
        });
        return new connectManagerEventMapper_1.PrepareConnectManagerEventMapper(observable)
            .map()
            .pipe((0, rxjs_1.concatWith)(cmd(transport, { deviceId, deviceName, request })));
    });
}
exports.default = connectManagerFactory;
//# sourceMappingURL=connectManager.js.map