"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Api = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const react_router_dom_1 = require("react-router-dom");
const react_error_boundary_1 = require("react-error-boundary");
const ui_keyring_1 = __importDefault(require("@polkadot/ui-keyring"));
const extension_dapp_1 = require("@polkadot/extension-dapp");
const polymesh_sdk_1 = require("@polymathnetwork/polymesh-sdk");
const polymesh_ui_1 = require("@polymathnetwork/polymesh-ui");
const lodash_orderby_1 = __importDefault(require("lodash.orderby"));
const getChainProperties_1 = require("../utils/getChainProperties");
const keyLabelStorage_1 = require("../utils/keyLabelStorage");
const definition_1 = require("./definition");
const requiredApiActions = [
    'setSdk',
    'setCurrentAccount',
    'setCurrentIdentity',
    'setIsDidValid',
    'setDidIssuer',
    'setDidExpiry',
    'setHasUid',
    'setInFlight',
    'setPolyWallet',
    'setChainProperties',
];
const delay = (ms) => __awaiter(void 0, void 0, void 0, function* () { return new Promise((resolve) => setTimeout(resolve, ms)); });
let network;
let polyWallet;
let unsubAccountBalance;
const Api = ({ children, appName, apiConfig, apiActions }) => {
    const [isReady, setIsReady] = (0, react_1.useState)(false);
    const handleError = (0, react_error_boundary_1.useErrorHandler)();
    const history = (0, react_router_dom_1.useHistory)();
    const { polyWssNodeUrl, graphqlEndpoint, graphqlApiKey, masqueradeEnv, isProdEnv, rpcUrl, ss58FormatOverride, LoadingScreen = polymesh_ui_1.LoadingScreen, } = apiConfig;
    (0, react_1.useEffect)(() => {
        const { search } = window.location;
        const params = new URLSearchParams(search);
        const masqueradeQuery = params.get('masq');
        const masquerade = masqueradeQuery || masqueradeEnv;
        function connect(address, keyring, signer) {
            return __awaiter(this, void 0, void 0, function* () {
                apiActions.setCurrentAccount(address);
                const sdk = yield polymesh_sdk_1.Polymesh.connect({
                    nodeUrl: polyWssNodeUrl,
                    signer,
                    keyring,
                    middleware: {
                        link: graphqlEndpoint,
                        key: graphqlApiKey,
                    },
                });
                sdk.onDisconnect(() => __awaiter(this, void 0, void 0, function* () {
                    if (window.navigator.onLine) {
                        yield connect(address, keyring, signer);
                    }
                    else {
                        const reconnect = () => __awaiter(this, void 0, void 0, function* () {
                            yield connect(address, keyring, signer);
                            window.removeEventListener('online', reconnect);
                        });
                        window.addEventListener('online', reconnect);
                    }
                }));
                apiActions.setSdk(sdk);
                unsubAccountBalance = yield sdk.getAccountBalance((balance) => {
                    apiActions.setAccountBalance(balance);
                });
                setIsReady(true);
                try {
                    const identity = yield sdk.getCurrentIdentity();
                    if (identity) {
                        apiActions.setCurrentIdentity(identity);
                        const hasUid = yield polyWallet.uid.isSet();
                        apiActions.setHasUid(hasUid);
                        if (!hasUid) {
                            history.push(definition_1.AppStaticRoute.uIdMissing, {
                                polyWallet,
                                did: identity.did,
                                network,
                            });
                        }
                        const isDidValid = yield sdk.isIdentityValid({
                            identity: identity.did,
                        });
                        apiActions.setIsDidValid(isDidValid);
                        const cddAttestations = yield sdk.claims.getCddClaims({
                            target: identity,
                        });
                        const cddAttestation = (0, lodash_orderby_1.default)(cddAttestations, ['expiry'], ['desc'])[0];
                        apiActions.setDidIssuer(cddAttestation === null || cddAttestation === void 0 ? void 0 : cddAttestation.issuer);
                        apiActions.setDidExpiry((cddAttestation === null || cddAttestation === void 0 ? void 0 : cddAttestation.expiry) || undefined);
                        const currentAccount = sdk.getAccount();
                        const currentPermissions = yield currentAccount.getPermissions();
                        apiActions.setPermissions(currentPermissions);
                    }
                    else {
                        apiActions.setIsDidValid(false);
                    }
                }
                catch (error) {
                    apiActions.setIsDidValid(false);
                }
            });
        }
        function init() {
            return __awaiter(this, void 0, void 0, function* () {
                try {
                    yield delay(500);
                    const extensions = yield (0, extension_dapp_1.web3Enable)(appName);
                    if (!masquerade && (!extensions || extensions.length === 0)) {
                        history.push(definition_1.AppStaticRoute.extension);
                    }
                    polyWallet = extensions.filter((ext) => ext.name === 'polywallet')[0];
                    if (polyWallet) {
                        apiActions.setPolyWallet(polyWallet);
                        const networkMeta = yield polyWallet.network.get();
                        const cleanEndpoint = networkMeta.wssUrl.replace(/\/$/, '');
                        const cleanUrl = polyWssNodeUrl.replace(/\/$/, '');
                        if (cleanUrl !== cleanEndpoint) {
                            history.push(definition_1.AppStaticRoute.wrongNetwork);
                        }
                        network = networkMeta.name;
                        if (window.location.hostname !== 'localhost') {
                            polyWallet.network.subscribe(() => {
                                window.location.reload();
                            });
                            polyWallet.accounts.subscribe(() => {
                                window.location.reload();
                            });
                        }
                    }
                    else if (!masquerade) {
                        history.push(definition_1.AppStaticRoute.extension);
                    }
                    const chainProperties = yield (0, getChainProperties_1.getChainProperties)(rpcUrl);
                    if (ss58FormatOverride) {
                        chainProperties.ss58Format = Number(ss58FormatOverride);
                    }
                    apiActions.setChainProperties(chainProperties);
                    const { ss58Format } = chainProperties;
                    const keyring = new polymesh_sdk_1.Keyring({ type: 'ed25519', ss58Format });
                    let address;
                    let signer;
                    if (masquerade && !isProdEnv) {
                        try {
                            ui_keyring_1.default.loadAll({
                                type: 'ed25519',
                                isDevelopment: true,
                            });
                        }
                        catch (error) {
                            // This try-catch is needed to enable use of browser navigation buttons.
                            // You can't initialize `keyring` more than once, and using an `if` statement
                            // broke things because it couldn't find the test account `alice`.
                        }
                        const allTestingPairs = ui_keyring_1.default.getPairs();
                        const testingAccountPair = allTestingPairs.filter(({ meta: { name, isTesting } }) => name === masquerade && isTesting === true)[0];
                        keyring.addPair(testingAccountPair);
                        if (testingAccountPair) {
                            address = testingAccountPair.address;
                            connect(address, keyring, signer);
                        }
                        else {
                            throw new Error(`Couldn't find test account ${masquerade}`);
                        }
                    }
                    else {
                        const accounts = (yield (0, extension_dapp_1.web3Accounts)({ ss58Format })).filter((account) => account.meta.source === 'polywallet');
                        if (accounts[0]) {
                            const account = accounts === null || accounts === void 0 ? void 0 : accounts[0];
                            if (!account)
                                throw new Error('Account not found');
                            address = account.address;
                            if (account.meta.name)
                                keyLabelStorage_1.keyLabel.save(address, account.meta.name);
                            keyring.addFromAddress(address);
                            const injector = yield (0, extension_dapp_1.web3FromAddress)(address);
                            signer = injector.signer;
                            connect(address, keyring, signer);
                        }
                    }
                }
                catch (error) {
                    // Display error via ErrorBoundary fallback component.
                    handleError(error);
                }
            });
        }
        const providedActions = Object.keys(apiActions);
        const missingActions = requiredApiActions.filter((a) => !providedActions.includes(a));
        if (missingActions.length) {
            throw new Error(`Missing actions for API to init: ${missingActions.join(', ')}`);
        }
        else {
            init();
        }
        return () => {
            if (unsubAccountBalance)
                unsubAccountBalance();
        };
    }, []); // eslint-disable-line
    if (isReady)
        return children;
    else
        return (0, jsx_runtime_1.jsx)(LoadingScreen, {}, void 0);
};
exports.Api = Api;
//# sourceMappingURL=Api.js.map