/**
 * @module sync-innerspace.respec
 *
 * Verifies SyncSagaCoordinator using InnerSpace (in-memory/local) spaces.
 * This utilizes SyncPeerInnerspace_V1 for local-to-local synchronization simulations.
 */
import { respecfully, ifWe, iReckon } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
const maam = `[${import.meta.url}]`, sir = maam;
import { clone, delay, extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
import { SyncSagaCoordinator } from './sync-saga-coordinator.mjs';
import { getFromSpace } from '../witness/space/space-helper.mjs';
import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
import { createTimelineRootTestHelper, } from '../test-helpers.mjs';
import { mut8Timeline, } from '../timeline/timeline-api.mjs';
import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
import { toDto } from '../common/other/ibgib-helper.mjs';
import { fnObs } from '../common/pubsub/observer/observer-helper.mjs';
import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
const logalot = GLOBAL_LOG_A_LOT;
const lc = `[sync-innerspace.respec]`;
await respecfully(sir, `Sync InnerSpaces`, async () => {
    let metaspace;
    let sourceSpace;
    let destSpace;
    await respecfully(sir, `Basic Push Sync (Source -> Dest)`, async () => {
        // 1. Setup Spaces
        metaspace = new Metaspace_Innerspace(undefined);
        await metaspace.initialize({
            getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
            getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
            getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
        });
        while (!metaspace.initialized) {
            await delay(10);
        }
        const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
        if (!defaultLocalUserSpace) {
            throw new Error(`(UNEXPECTED) defaultLocalUserSpace falsy? (E: 56f019430b29b45147e0caa4d5931826)`);
        }
        await defaultLocalUserSpace.initialized;
        if (logalot) {
            console.log(`defaultLocalUserSpace: ${pretty(toDto({ ibGib: defaultLocalUserSpace }))}`);
        }
        sourceSpace = new InnerSpace_V1({
            ...DEFAULT_INNER_SPACE_DATA_V1,
            name: 'source',
            uuid: 'source_uuid',
            description: 'source test space',
        });
        await sourceSpace.initialized;
        if (logalot) {
            console.log(`sourceSpace: ${pretty(toDto({ ibGib: sourceSpace }))}`);
        }
        // await (sourceSpace as any).initialize(); // DO NOT AWAIT THIS. THIS IS AUTOMATICALLY AWAITED IN PLUMBING
        destSpace = new InnerSpace_V1({
            ...DEFAULT_INNER_SPACE_DATA_V1,
            name: 'dest',
            uuid: 'dest_uuid',
            description: 'dest test space',
        });
        await destSpace.initialized;
        if (logalot) {
            console.log(`destSpace: ${pretty(toDto({ ibGib: destSpace }))}`);
        }
        // await (destSpace as any).initialized; // DO NOT AWAIT THIS. THIS IS AUTOMATICALLY AWAITED IN PLUMBING
        // 2. Seed Source Data
        if (logalot) {
            console.log(`${lc} Creating data in Source...`);
        }
        const root = await createTimelineRootTestHelper({
            ib: 'timeline_root',
            // data: { type: 'root', n: 0 }, // DO NOT TRY TO MANUALLY SET n
            data: { type: 'root', },
            space: sourceSpace,
        });
        const child = await mut8Timeline({
            timeline: root,
            mut8Opts: {
                // dataToAddOrPatch: { type: 'child', n: 1 }, // DO NOT TRY TO MANUALLY SET n
                dataToAddOrPatch: { type: 'child', },
            },
            metaspace,
            space: sourceSpace,
        });
        const childAddr = getIbGibAddr({ ibGib: child });
        // 3. Setup Coordinators & Peer
        if (logalot) {
            console.log(`${lc} Setting up Coordinators...`);
        }
        // Sender Coordinator
        const senderCoordinator = new SyncSagaCoordinator();
        // Receiver Coordinator
        // Note: Receiver acts "globally" usually, but here we treat it as bound to the dest operations?
        // Actually SyncSagaCoordinator isn't bound to a space. It works ON a space.
        // So we can reuse or create separate instances. Let's create separate to simulate remote.
        const receiverCoordinator = new SyncSagaCoordinator();
        // Peer (The "Network")
        const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
        await peer.initialized;
        await peer.initializeOpts({
            localMetaspace: metaspace,
            localSpace: sourceSpace, // "Client"
            receiverSpace: destSpace, // "Server"
            receiverCoordinator,
            receiverMetaspace: metaspace,
        });
        // 4. Run Sync
        if (logalot) {
            console.log(`${lc} Running Sync...`);
        }
        const resSync = await senderCoordinator.sync({
            peer: peer,
            localSpace: sourceSpace,
            metaspace: metaspace,
            domainIbGibs: [child], // Sync the child
        }); // Type cast if needed until we align optional params
        if (logalot) {
            console.log(`${lc} resSync: ${pretty(resSync)}`);
        }
        const sublc = `${lc}[updates$]`;
        /**
         * I have added this so you can see how to subscribe to an ibgib
         * observable using {@link fnObs}.
         */
        const subscription = await resSync.updates$.subscribe(fnObs({
            next: async (ctxIbGib) => {
                if (logalot) {
                    console.log(`${sublc} next fired`);
                }
            },
            error: async (e) => {
                if (logalot) {
                    console.log(`${sublc} error fired`);
                }
            },
            complete: async () => {
                if (logalot) {
                    console.log(`${sublc} complete fired`);
                }
            },
        }));
        if (logalot) {
            console.log(`${lc} awaiting resSync.done`);
        }
        await resSync.done;
        // todo: add iReckon assertions about resSync
        // 5. Verify Dest
        if (logalot) {
            console.log(`${lc} Verifying Destination...`);
        }
        try {
            const getChildInDest = await getFromSpace({ space: destSpace, addr: childAddr });
            await ifWe(sir, `verify success getChildInDest`, async () => {
                iReckon(sir, getChildInDest.success).asTo('Child present in Dest').isGonnaBeTrue();
            });
            await ifWe(sir, `verify getChildInDest.ibGibs`, async () => {
                const firstChild = getChildInDest.ibGibs?.[0];
                if (logalot) {
                    console.log(`${lc} firstChild: ${pretty(firstChild)}`);
                }
                iReckon(sir, firstChild?.data?.n).asTo('Child content matches').isGonnaBe(2);
            });
        }
        catch (error) {
            await ifWe(sir, `doh`, async () => {
                // hack here I'm getting tired...
                iReckon(sir, true).asTo(`error: ${extractErrorMsg(error)}`).isGonnaBeFalse();
            });
        }
        finally {
            if (logalot) {
                console.log(`${lc} Test complete.`);
            }
        }
    });
});
//# sourceMappingURL=sync-innerspace.respec.mjs.map