"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const errors_1 = require("@ledgerhq/errors");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const network_1 = __importDefault(require("@ledgerhq/live-network/network"));
const errors_2 = require("../errors");
const api_1 = __importDefault(require("../manager/api"));
const attemptToQuitApp_1 = __importDefault(require("./attemptToQuitApp"));
const deviceAccess_1 = require("./deviceAccess");
const getAppAndVersion_1 = __importDefault(require("./getAppAndVersion"));
const getDeviceInfo_1 = __importDefault(require("./getDeviceInfo"));
const isDashboardName_1 = require("./isDashboardName");
function installLanguage({ deviceId, deviceName, request, }) {
    const { language } = request;
    const sub = (0, deviceAccess_1.withDevice)(deviceId, deviceName ? { matchDeviceByName: deviceName } : undefined)(transport => new rxjs_1.Observable(subscriber => {
        const timeoutSub = (0, rxjs_1.of)({
            type: "unresponsiveDevice",
        })
            .pipe((0, operators_1.delay)(1000))
            .subscribe(e => subscriber.next(e));
        const sub = (0, rxjs_1.from)((0, getDeviceInfo_1.default)(transport))
            .pipe((0, operators_1.mergeMap)(async (deviceInfo) => {
            timeoutSub.unsubscribe();
            if (language === "english") {
                await uninstallAllLanguages(transport);
                subscriber.next({
                    type: "languageInstalled",
                });
                subscriber.complete();
                return;
            }
            const languages = await api_1.default.getLanguagePackagesForDevice(deviceInfo);
            const packs = languages.filter((l) => l.language === language);
            if (!packs.length)
                return subscriber.error(new errors_1.LanguageNotFound(language));
            const pack = packs[0];
            const { apdu_install_url } = pack;
            const url = apdu_install_url;
            const { data: rawApdus } = await (0, network_1.default)({
                method: "GET",
                url,
            });
            const apdus = rawApdus.split(/\r?\n/).filter(Boolean);
            await uninstallAllLanguages(transport);
            for (let i = 0; i < apdus.length; i++) {
                if (apdus[i].startsWith("e030")) {
                    subscriber.next({
                        type: "devicePermissionRequested",
                    });
                }
                const response = await transport.exchange(Buffer.from(apdus[i], "hex"));
                const status = response.readUInt16BE(response.length - 2);
                const statusStr = status.toString(16);
                // Some error handling
                if (status === errors_1.StatusCodes.USER_REFUSED_ON_DEVICE) {
                    return subscriber.error(new errors_2.LanguageInstallRefusedOnDevice(statusStr));
                }
                else if (status === errors_1.StatusCodes.NOT_ENOUGH_SPACE) {
                    return subscriber.error(new errors_1.ManagerNotEnoughSpaceError());
                }
                else if (status !== errors_1.StatusCodes.OK) {
                    return subscriber.error(new errors_1.TransportError("Unexpected device response", statusStr));
                }
                subscriber.next({
                    type: "progress",
                    progress: (i + 1) / apdus.length,
                });
            }
            subscriber.next({
                type: "languageInstalled",
            });
            subscriber.complete();
        }), (0, operators_1.catchError)((e) => {
            if (e instanceof errors_1.DeviceOnDashboardExpected ||
                (e &&
                    e instanceof errors_1.TransportStatusError &&
                    [0x6e00, 0x6d00, 0x6e01, 0x6d01, 0x6d02].includes(e.statusCode))) {
                return (0, rxjs_1.from)((0, getAppAndVersion_1.default)(transport)).pipe((0, operators_1.concatMap)(appAndVersion => {
                    return !(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(subscriber);
        return () => {
            timeoutSub.unsubscribe();
            sub.unsubscribe();
        };
    }));
    return sub;
}
exports.default = installLanguage;
const uninstallAllLanguages = async (transport) => {
    await transport.send(0xe0, 0x33, 0xff, 0x00, undefined, [0x9000, 0x5501]);
};
//# sourceMappingURL=installLanguage.js.map