"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const hw_transport_mocker_1 = require("@ledgerhq/hw-transport-mocker");
const operators_1 = require("rxjs/operators");
const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
const scenarios_mock_1 = __importDefault(require("./scenarios.mock"));
const _1 = require(".");
const rxjs_1 = require("rxjs");
/**
 * Both ends of the exchange are mocked in this test file and we are merely testing
 * the logic that happens in-between.
 */
jest.mock("isomorphic-ws", () => ({
    ...jest.requireActual("isomorphic-ws"),
    __esModule: true,
    default: jest.fn(),
}));
describe("Scriptrunner logic", () => {
    scenarios_mock_1.default.forEach(({ describe, device, events }) => {
        it(describe, async () => {
            // Generate a transport replayer with the data from the test
            const transport = await (0, hw_transport_mocker_1.openTransportReplayer)(hw_transport_mocker_1.RecordStore.fromString(device));
            isomorphic_ws_1.default.mockImplementation(() => {
                let msgIndex = 0;
                // Exposed WebSocket callbacks:
                // - `on*` are implemented inside `createDeviceSocket`
                // - `send` is used to send back messages to the HSM
                // - `close` is used to close the connection with the HSM
                const callbacks = {
                    onopen: undefined,
                    onerror: undefined,
                    onclose: undefined,
                    onmessage: undefined,
                    send: undefined,
                    close: () => undefined,
                };
                callbacks.send = _ => {
                    // Iterates to the next scenario event once the fake device sends a response to the HSM
                    msgIndex++;
                    const [callback, payload] = events[msgIndex];
                    const nextEvent = events[msgIndex + 1];
                    const [nextEventCallback, nextEventPayload, nextEventEager] = nextEvent
                        ? nextEvent
                        : [undefined, undefined, undefined];
                    let isExchangeBlocked = false;
                    // The next event (from the HSM) is an allow secure channel
                    if (payload?.includes("e051000000")) {
                        // Needs to delay the next APDU to see the allow secure channel event.
                        transport.setArtificialExchangeDelay(1000);
                    }
                    // If the current message is a bulk, and we want the HSM to send a message (like success) directly after,
                    // we slowdown
                    if (payload?.includes("bulk") && nextEventEager) {
                        isExchangeBlocked = true;
                        transport.enableExchangeBlocker();
                    }
                    const maybeCallback = callbacks[callback];
                    if (maybeCallback) {
                        maybeCallback({ data: payload });
                    }
                    // Checks if the next event should be emitted straight away instead of as
                    // a (device) response to the current event HSM message.
                    // This is used to trigger errors and closing the connection from the scriptrunner side.
                    if (nextEvent && nextEventCallback) {
                        const maybeCallback = callbacks[nextEventCallback];
                        if (maybeCallback && nextEventEager) {
                            if (isExchangeBlocked) {
                                maybeCallback({ data: nextEventPayload });
                                transport.unblockExchange();
                                isExchangeBlocked = false;
                            }
                            else {
                                setTimeout(() => {
                                    // Emits without any further device interaction
                                    maybeCallback({ data: nextEventPayload });
                                }, 200);
                            }
                        }
                    }
                };
                // Starts the fake WebSocket communication with the HSM
                setTimeout(() => {
                    if (callbacks.onopen) {
                        callbacks.onopen(null);
                        const [callback, payload] = events[msgIndex];
                        const maybeCallback = callbacks[callback];
                        if (maybeCallback) {
                            maybeCallback({ data: payload });
                        }
                    }
                }, 0);
                return callbacks;
            });
            // Mock the socket connection
            try {
                const resolved = await (0, rxjs_1.firstValueFrom)((0, _1.createDeviceSocket)(transport, {
                    url: "no-need-for-a-url",
                }).pipe((0, operators_1.toArray)()));
                expect(resolved).toMatchSnapshot();
            }
            catch (error) {
                expect(error).toMatchSnapshot();
            }
            return;
        });
    });
});
//# sourceMappingURL=socket.test.js.map