import { of } from "rxjs";
import { scan, catchError, tap } from "rxjs/operators";
import { useEffect, useState } from "react";
import { log } from "@ledgerhq/logs";
import { TransportStatusError } from "@ledgerhq/errors";
import { TransactionRefusedOnDevice } from "../../errors";
import { getMainAccount } from "../../account";
import { getAccountBridge } from "../../bridge";
import { createAction as createAppAction } from "./app";
import { bridge as ACREBridge } from "../../families/bitcoin/ACRESetup";
const mapResult = ({ device, signedOperation, transactionSignError, }) => signedOperation && device
    ? {
        signedOperation,
        device,
    }
    : transactionSignError
        ? {
            transactionSignError,
        }
        : null;
const initialState = {
    signedOperation: null,
    deviceSignatureRequested: false,
    deviceStreamingProgress: null,
    transactionSignError: null,
    transactionChecksOptInTriggered: false,
    transactionChecksOptIn: null,
};
const reducer = (state, e) => {
    switch (e.type) {
        case "error": {
            const { error } = e;
            const transactionSignError = error instanceof TransportStatusError && error.statusCode === 0x6985
                ? new TransactionRefusedOnDevice()
                : error;
            return { ...initialState, transactionSignError };
        }
        case "signed":
            return { ...state, signedOperation: e.signedOperation };
        case "device-signature-requested":
            return { ...state, deviceSignatureRequested: true };
        case "device-signature-granted":
            return { ...state, deviceSignatureRequested: false };
        case "device-streaming":
            return { ...state, deviceStreamingProgress: e.progress };
        case "transaction-checks-opt-in-triggered":
            return { ...state, transactionChecksOptInTriggered: true };
        case "transaction-checks-opt-in":
            return { ...state, transactionChecksOptIn: true };
        case "transaction-checks-opt-out":
            return { ...state, transactionChecksOptIn: false };
        default:
            return state;
    }
};
export const createAction = (connectAppExec) => {
    const useHook = (reduxDevice, txRequest) => {
        const { transaction, appName, dependencies, requireLatestFirmware, manifestId, manifestName, isACRE, } = txRequest;
        const mainAccount = getMainAccount(txRequest.account, txRequest.parentAccount);
        const appState = createAppAction(connectAppExec).useHook(reduxDevice, {
            account: isACRE ? undefined : mainAccount,
            appName,
            dependencies,
            requireLatestFirmware,
        });
        const { device, opened, inWrongDeviceForAccount, error } = appState;
        const [state, setState] = useState(initialState);
        useEffect(() => {
            if (!device || !opened || inWrongDeviceForAccount || error) {
                setState(initialState);
                return;
            }
            const bridge = isACRE
                ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    ACREBridge.accountBridge
                : getAccountBridge(mainAccount);
            const sub = bridge
                .signOperation({
                account: mainAccount,
                transaction,
                deviceId: device.deviceId,
                deviceModelId: device.modelId,
            })
                .pipe(catchError(error => of({
                type: "error",
                error,
            })), tap((e) => log("actions-transaction-event", e.type, e)), scan(reducer, initialState))
                .subscribe((x) => setState(x));
            return () => {
                sub.unsubscribe();
            };
        }, [device, mainAccount, transaction, opened, inWrongDeviceForAccount, error, isACRE]);
        return {
            ...appState,
            ...state,
            manifestId,
            manifestName,
            deviceStreamingProgress: state.signedOperation || state.transactionSignError
                ? null // when good app is opened, we start the progress so it doesn't "blink"
                : state.deviceStreamingProgress || (appState.opened ? 0 : null),
        };
    };
    return {
        useHook,
        mapResult,
    };
};
//# sourceMappingURL=transaction.js.map