/**
 * @module sync-innerspace-dest-ahead.respec
 *
 * Verifies Complex Sync Scenarios using InnerSpace.
 */
import { respecfully, ifWe, iReckon } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
const maam = `[${import.meta.url}]`, sir = maam;
import { clone, delay, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
import { SyncSagaCoordinator } from './sync-saga-coordinator.mjs';
import { putInSpace, getFromSpace, registerNewIbGib } 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 { 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';
import { getDependencyGraph } from '../common/other/graph-helper.mjs';
const logalot = false;
const lc = `[sync-innerspace-dest-ahead.respec]`;
await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
    let metaspace;
    let sourceSpace;
    let destSpace;
    await respecfully(sir, `Dest Ahead (Remote Newer)`, async () => {
        // 1. Setup Spaces
        metaspace = new Metaspace_Innerspace(undefined);
        await metaspace.initialize({
            getFnAlert: () => async ({ title, msg }) => { },
            getFnPrompt: () => async ({ title, msg }) => { return ''; },
            getFnPromptPassword: () => async (title, msg) => { return null; },
        });
        while (!metaspace.initialized) {
            await delay(10);
        }
        const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
        await defaultLocalUserSpace.initialized;
        sourceSpace = new InnerSpace_V1({
            ...DEFAULT_INNER_SPACE_DATA_V1,
            name: 'source',
            uuid: 'source_uuid',
            description: 'source test space',
        });
        await sourceSpace.initialized;
        destSpace = new InnerSpace_V1({
            ...DEFAULT_INNER_SPACE_DATA_V1,
            name: 'dest',
            uuid: 'dest_uuid',
            description: 'dest test space',
        });
        await destSpace.initialized;
        // 2. Seed Data
        // Root -> V1 (Shared) -> V2 (Dest has New)
        // Source only has V1.
        const v0 = await createTimelineRootTestHelper({
            ib: 'timeline_root_ff',
            data: { type: 'root', label: 'Root' },
            space: sourceSpace,
        });
        const addrV0 = getIbGibAddr({ ibGib: v0 });
        console.log(pretty(v0));
        // V1 (Both have it, but we create in source and copy to dest)
        const v1 = await mut8Timeline({
            timeline: v0,
            mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V1' } },
            metaspace,
            space: sourceSpace,
        });
        const addrV1 = getIbGibAddr({ ibGib: v1 });
        console.log(pretty(v1));
        // Transfer Root & V1 to Dest
        const initialDepGraph = await getDependencyGraph({ ibGibs: [v0, v1], space: sourceSpace });
        await putInSpace({ space: destSpace, ibGibs: Object.values(initialDepGraph) }); // Naive seeding
        await registerNewIbGib({ space: destSpace, ibGib: v0 });
        await registerNewIbGib({ space: destSpace, ibGib: v1 });
        // V2 (Created in Dest ONLY)
        const v2 = await mut8Timeline({
            timeline: v1, // v1 is in memory, linked to source, but we want to Mutate IN DEST SPACE
            mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V2' } },
            metaspace,
            space: destSpace, // Mutate in Dest
        });
        const addrV2 = getIbGibAddr({ ibGib: v2 });
        console.log(pretty(v2));
        const fnAddrExistsInSpace = async (addr, space) => {
            const resGet = await getFromSpace({ addr, space });
            return resGet.success && resGet.ibGibs && resGet.ibGibs.length === 1;
        };
        await ifWe(sir, 'verify setup', async () => {
            // Ensure V2 is ONLY in Dest (it is, per `space: destSpace`)
            // Ensure Source does NOT have V2
            iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV1, sourceSpace)).asTo('source has V1').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV2, sourceSpace)).asTo('source has V2').isGonnaBeFalse();
            iReckon(sir, await fnAddrExistsInSpace(addrV0, destSpace)).asTo('dest has V0').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV1, destSpace)).asTo('dest has V1').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV2, destSpace)).asTo('dest has V2').isGonnaBeTrue();
        });
        // 3. Setup Sync
        const senderCoordinator = new SyncSagaCoordinator();
        const receiverCoordinator = new SyncSagaCoordinator();
        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 (Source Pushes V1)
        console.log(`${lc} Running Sync...`);
        const { done, sagaId, updates$ } = await senderCoordinator.sync({
            peer: peer,
            localSpace: sourceSpace,
            metaspace: metaspace,
            domainIbGibs: [v1], // Source tries to push V1
        });
        await done;
        // 5. Verify Sync (v2 should be in both source and dest now)
        console.log(`${lc} Verifying Sync...`);
        await ifWe(sir, `verify v2 now also in source`, async () => {
            // Verify Tip (V2)
            iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV1, sourceSpace)).asTo('source has V1').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV2, sourceSpace)).asTo('source has V2').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV0, destSpace)).asTo('dest has V0').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV1, destSpace)).asTo('dest has V1').isGonnaBeTrue();
            iReckon(sir, await fnAddrExistsInSpace(addrV2, destSpace)).asTo('dest has V2').isGonnaBeTrue();
        });
        await ifWe(sir, `dependency graphs the same`, async () => {
            const sourceDepGraph = await getDependencyGraph({
                ibGibAddr: addrV2,
                space: sourceSpace,
            });
            const destDepGraph = await getDependencyGraph({
                ibGibAddr: addrV2,
                space: destSpace,
            });
            const sourceDepGraphAddrs = Object.keys(sourceDepGraph);
            const destDepGraphAddrs = Object.keys(destDepGraph);
            iReckon(sir, sourceDepGraphAddrs.length === destDepGraphAddrs.length).asTo('dep graphs same size').isGonnaBeTrue();
            sourceDepGraphAddrs.forEach(sourceDepAddr => {
                iReckon(sir, destDepGraphAddrs.includes(sourceDepAddr)).asTo(`${sourceDepAddr} is both graphs`).isGonnaBeTrue();
            });
        });
    });
});
//# sourceMappingURL=sync-innerspace-dest-ahead.respec.mjs.map