"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAppUninstallNeedsDeps = exports.useAppInstallNeedsDeps = exports.useAppInstallProgress = exports.useAppsSections = exports.useNotEnoughMemoryToInstall = exports.useAppsRunner = void 0;
const react_1 = require("react");
const filtering_1 = require("./filtering");
const logic_1 = require("./logic");
const runner_1 = require("./runner");
const featureFlags_1 = require("../featureFlags");
// use for React apps. support dynamic change of the state.
const useAppsRunner = (listResult, exec, appsToRestore) => {
    // $FlowFixMe for ledger-live-mobile older react/flow version
    const [state, dispatch] = (0, react_1.useReducer)(logic_1.reducer, null, () => (0, logic_1.initState)(listResult, appsToRestore));
    const nextAppOp = (0, react_1.useMemo)(() => (0, logic_1.getNextAppOp)(state), [state]);
    const appOp = state.currentAppOp || nextAppOp;
    (0, react_1.useEffect)(() => {
        dispatch({
            type: "reset",
            initialState: (0, logic_1.initState)(listResult, appsToRestore),
        });
    }, [listResult, appsToRestore]);
    (0, react_1.useEffect)(() => {
        if (appOp) {
            const sub = (0, runner_1.runAppOp)({ state, appOp, exec }).subscribe(event => {
                dispatch({
                    type: "onRunnerEvent",
                    event,
                });
            });
            return () => {
                sub.unsubscribe();
            };
        } // we only want to redo the effect on appOp changes here
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [listResult, appOp, exec]);
    return [state, dispatch];
};
exports.useAppsRunner = useAppsRunner;
function useNotEnoughMemoryToInstall(state, name) {
    return (0, react_1.useMemo)(() => (0, logic_1.isOutOfMemoryState)((0, logic_1.predictOptimisticState)((0, logic_1.reducer)(state, {
        type: "install",
        name,
    }))), [name, state]);
}
exports.useNotEnoughMemoryToInstall = useNotEnoughMemoryToInstall;
function useAppsSections(state, opts) {
    const { updateAllQueue, appByName, installed, installQueue, apps } = state;
    const appsUpdating = (0, react_1.useMemo)(() => updateAllQueue.map(name => appByName[name]).filter(Boolean), [appByName, updateAllQueue]);
    const updatableAppList = (0, react_1.useMemo)(() => apps.filter(({ name }) => installed.some(i => i.name === name && !i.updated)), [apps, installed]);
    const { getFeature, isFeature } = (0, featureFlags_1.useFeatureFlags)();
    const update = appsUpdating.length > 0 ? appsUpdating : updatableAppList;
    const filterParam = (0, react_1.useMemo)(() => ({
        query: opts.query,
        installedApps: installed,
        type: [opts.appFilter],
        getFeature,
        isFeature,
    }), [getFeature, installed, isFeature, opts.appFilter, opts.query]);
    const catalog = (0, filtering_1.useSortedFilteredApps)(apps, filterParam, opts.sort);
    const installedAppList = (0, filtering_1.useSortedFilteredApps)(apps, {
        query: opts.query,
        installedApps: installed,
        installQueue,
        type: ["installed"],
        getFeature,
        isFeature,
    }, {
        type: "default",
        order: "asc",
    });
    const device = installedAppList.sort(({ name: _name }, { name }) => {
        // place install queue on top of list
        // with the app being installed at the top
        let pos1 = installQueue.indexOf(_name);
        let pos2 = installQueue.indexOf(name);
        pos1 = pos1 < 0 ? Number.MAX_VALUE : pos1;
        pos2 = pos2 < 0 ? Number.MAX_VALUE : pos2;
        return pos1 - pos2;
    });
    return {
        update,
        catalog,
        device,
    };
}
exports.useAppsSections = useAppsSections;
function useAppInstallProgress(state, name) {
    const { currentProgressSubject, currentAppOp } = state;
    const [progress, setProgress] = (0, react_1.useState)(0);
    (0, react_1.useEffect)(() => {
        if (!currentAppOp || !currentProgressSubject || currentAppOp.name !== name) {
            setProgress(0);
            return;
        }
        const sub = currentProgressSubject.subscribe(setProgress);
        return () => sub.unsubscribe();
    }, [currentProgressSubject, currentAppOp, name]);
    if (currentProgressSubject && currentAppOp && currentAppOp.name === name) {
        return progress;
    }
    return 0;
}
exports.useAppInstallProgress = useAppInstallProgress;
// if the app needs deps to be installed, we want to display a modal
// this should returns all params the modal also need (so we don't do things twice)
function useAppInstallNeedsDeps(state, app) {
    const { appByName, installed: installedList, installQueue } = state;
    const res = (0, react_1.useMemo)(() => {
        const dependencies = (app.dependencies || [])
            .map(name => appByName[name])
            .filter(dep => dep &&
            !installedList.some(app => app.name === dep.name) &&
            !installQueue.includes(dep.name));
        if (dependencies.length) {
            return {
                app,
                dependencies,
            };
        }
        return null;
    }, [appByName, app, installQueue, installedList]);
    return res;
}
exports.useAppInstallNeedsDeps = useAppInstallNeedsDeps;
// if the app needs deps to be installed, we want to display a modal
// this should returns all params the modal also need (so we don't do things twice)
function useAppUninstallNeedsDeps(state, app) {
    const { apps, installed } = state;
    const res = (0, react_1.useMemo)(() => {
        const dependents = apps.filter(a => installed.some(i => i.name === a.name) && a.dependencies.includes(app.name));
        if (dependents.length) {
            return {
                dependents,
                app,
            };
        }
        return null;
    }, [app, apps, installed]);
    return res;
}
exports.useAppUninstallNeedsDeps = useAppUninstallNeedsDeps;
//# sourceMappingURL=react.js.map