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());
    });
};
import React, { useContext, useEffect, useMemo, useState } from 'react';
import { useAppDispatch, useAppSelector } from './redux/hooks';
import { proxy } from 'comlink';
import BroadcastChannelListener from './backend/channels/BroadcastChannelListener';
import { CYBER } from './utils/config';
import { getIpfsOpts } from './ipfs/config';
import { selectCurrentAddress } from './redux/features/pocket';
import DbApiWrapper from './backend/services/dataSource/indexedDb/dbApiWrapper';
const createSenseApi = (dbApi, myAddress) => ({
    getSummary: () => dbApi.getSenseSummary(myAddress),
    getList: () => dbApi.getSenseList(myAddress),
    markAsRead: (id) => dbApi.senseMarkAsRead(myAddress, id),
    getAllParticles: (fields) => dbApi.getParticles(fields),
    getLinks: (cid) => dbApi.getLinks(cid),
    getTransactions: (neuron) => dbApi.getTransactions(neuron),
    getMyChats: (userAddress) => {
        if (!myAddress) {
            throw new Error('myAddress is not defined');
        }
        return dbApi.getMyChats(myAddress, userAddress);
    },
});
const setupStoragePersistence = () => __awaiter(void 0, void 0, void 0, function* () {
    let isPersistedStorage = yield navigator.storage.persisted();
    if (!isPersistedStorage) {
        yield navigator.permissions.query({ name: 'persistent-storage' });
        isPersistedStorage = yield navigator.storage.persisted();
    }
    const message = isPersistedStorage
        ? `🔰 Storage is persistent.`
        : `⚠️ Storage is non-persitent.`;
    console.log(message);
    return isPersistedStorage;
});
const valueContext = {
    isIpfsInitialized: false,
    isDbInitialized: false,
    isSyncInitialized: false,
    isReady: false,
    dbApi: null,
    senseApi: null,
    ipfsApi: null,
};
const BackendContext = React.createContext(valueContext);
export function useBackend() {
    return useContext(BackendContext);
}
const dbApi = new DbApiWrapper();
function BackendProvider({ children, backgroundWorkerInstance, cozoDbWorkerInstance }) {
    const dispatch = useAppDispatch();
    const [ipfsError, setIpfsError] = useState(null);
    const isDbInitialized = useAppSelector((state) => state.backend.services.db.status === 'started');
    const isIpfsInitialized = useAppSelector((state) => state.backend.services.ipfs.status === 'started');
    const isSyncInitialized = useAppSelector((state) => state.backend.services.sync.status === 'started');
    const isReady = isDbInitialized && isIpfsInitialized && isSyncInitialized;
    const myAddress = useAppSelector(selectCurrentAddress);
    const followings = useAppSelector(({ currentAccount }) => {
        const { friends, following } = currentAccount.community;
        return Array.from(new Set([...friends, ...following]));
    });
    useEffect(() => {
        backgroundWorkerInstance.setParams({ myAddress });
    }, [myAddress]);
    useEffect(() => {
        backgroundWorkerInstance.setParams({ followings });
    }, [followings]);
    useEffect(() => {
        isReady && console.log('🟢 Backend started.');
    }, [isReady]);
    useEffect(() => {
        const channel = new BroadcastChannelListener((msg) => dispatch(msg.data));
        backgroundWorkerInstance.setParams({
            cyberIndexUrl: CYBER.CYBER_INDEX_HTTPS,
        });
        (() => __awaiter(this, void 0, void 0, function* () {
            console.log(process.env.IS_DEV
                ? '🧪 Starting backend in DEV mode...'
                : '🧬 Starting backend in PROD mode...');
            yield setupStoragePersistence();
            const ipfsLoadPromise = () => __awaiter(this, void 0, void 0, function* () {
                const isInitialized = yield backgroundWorkerInstance.isInitialized();
                if (isInitialized) {
                    console.log('🔋 Background worker already active.');
                    return Promise.resolve();
                }
                return loadIpfs();
            });
            const cozoDbLoadPromise = () => __awaiter(this, void 0, void 0, function* () {
                const isInitialized = yield cozoDbWorkerInstance.isInitialized();
                if (isInitialized) {
                    console.log('🔋 CozoDb worker already active.');
                    return Promise.resolve();
                }
                return loadCozoDb();
            });
            Promise.all([ipfsLoadPromise(), cozoDbLoadPromise()]);
        }))();
        window.q = backgroundWorkerInstance.ipfsQueue;
    }, [dispatch]);
    const loadCozoDb = () => __awaiter(this, void 0, void 0, function* () {
        console.time('🔋 CozoDb worker started.');
        yield cozoDbWorkerInstance
            .init()
            .then(() => {
            dbApi.init(proxy(cozoDbWorkerInstance));
            backgroundWorkerInstance.init(proxy(dbApi));
        })
            .then(() => console.timeEnd('🔋 CozoDb worker started.'));
    });
    const loadIpfs = () => __awaiter(this, void 0, void 0, function* () {
        const ipfsOpts = getIpfsOpts();
        yield backgroundWorkerInstance.ipfsApi.stop();
        console.time('🔋 Ipfs started.');
        yield backgroundWorkerInstance.ipfsApi
            .start(ipfsOpts)
            .then(() => {
            setIpfsError(null);
            console.timeEnd('🔋 Ipfs started.');
        })
            .catch((err) => {
            setIpfsError(err);
            console.log(`☠️ Ipfs error: ${err}`);
        });
    });
    const senseApi = useMemo(() => (isDbInitialized ? createSenseApi(dbApi, myAddress) : null), [isDbInitialized, myAddress]);
    const valueMemo = useMemo(() => ({
        cozoDbRemote: cozoDbWorkerInstance,
        ipfsApi: backgroundWorkerInstance.ipfsApi,
        defferedDbApi: backgroundWorkerInstance.defferedDbApi,
        ipfsNode: isIpfsInitialized
            ? backgroundWorkerInstance.ipfsApi.getIpfsNode()
            : null,
        senseApi,
        loadIpfs,
        ipfsError,
        isIpfsInitialized,
        isDbInitialized,
        isSyncInitialized,
        isReady,
    }), [
        isReady,
        isIpfsInitialized,
        isDbInitialized,
        isSyncInitialized,
        ipfsError,
        myAddress,
    ]);
    return (React.createElement(BackendContext.Provider, { value: valueMemo }, children));
}
export default BackendProvider;
//# sourceMappingURL=backend.js.map