/**
 * @module sync-withid.connect.respec
 *
 * Phase 2 — `peer.connect()` (Transport Handshake)
 *
 * Goal: Verify that the connection phase executes without error. S's connect
 * pool remains undepleted (no-op on innerspace).
 *
 * @see libs/core-gib/src/sync/docs/security.md — Implementation Plan, Phase 2A
 */
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 } 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 { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
import { KeystoneService_V1 } from '../keystone/keystone-service-v1.mjs';
import { KEYSTONE_VERB_SYNC, POOL_ID_SYNC, POOL_ID_CONNECT, KEYSTONE_VERB_CONNECT, } from '../keystone/keystone-constants.mjs';
import { createStandardPoolConfig } from '../keystone/keystone-config-builder.mjs';
import { KeystoneReplenishStrategy } from '../keystone/keystone-types.mjs';
import { SyncConflictStrategy } from './sync-constants.mjs';
import { getIdentity_throwIfUndefined } from '../keystone/keystone-helpers.mjs';
import { Factory_V1 } from '@ibgib/ts-gib/dist/V1/factory.mjs';
const logalot = GLOBAL_LOG_A_LOT;
const lc = sir;
// ---------------------------------------------------------------------------
// Test-only identity constants
// ---------------------------------------------------------------------------
const SENDER_SECRET = 'test-sender-secret-phase1';
// ---------------------------------------------------------------------------
// Session keystone pool configs
// ---------------------------------------------------------------------------
const SESSION_CONNECT_POOL_CONFIG = createStandardPoolConfig({
    id: POOL_ID_CONNECT,
    salt: 'session-connect-salt-phase1',
    verbs: [KEYSTONE_VERB_CONNECT],
    size: 10,
    sequential: 1,
    random: 1,
    targetBinding: 2,
    replenishStrategy: KeystoneReplenishStrategy.deleteAll,
});
const SESSION_SYNC_POOL_CONFIG = createStandardPoolConfig({
    id: POOL_ID_SYNC,
    salt: 'session-sync-salt-phase1',
    verbs: [KEYSTONE_VERB_SYNC],
    size: 200,
    sequential: 1,
    random: 1,
    targetBinding: 2,
    replenishStrategy: KeystoneReplenishStrategy.topUp,
});
// ---------------------------------------------------------------------------
// Top-level senderIdentity (I) pool config
// ---------------------------------------------------------------------------
const SENDER_IDENTITY_SYNC_POOL_CONFIG = createStandardPoolConfig({
    id: POOL_ID_SYNC,
    salt: 'senderidentitysyncsaltphase1',
    verbs: [KEYSTONE_VERB_SYNC],
    size: 200,
    sequential: 1,
    random: 1,
    targetBinding: 2,
    replenishStrategy: KeystoneReplenishStrategy.topUp,
});
// ---------------------------------------------------------------------------
// Main test suite
// ---------------------------------------------------------------------------
await respecfully(sir, `Test Phase 2: peer.connect()`, async () => {
    // #region Init/Setup
    const 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 });
    await defaultLocalUserSpace.initialized;
    const sourceSpace = new InnerSpace_V1({
        ...DEFAULT_INNER_SPACE_DATA_V1,
        name: 'source',
        uuid: 'source_uuid',
        description: 'sender durable space',
    });
    await sourceSpace.initialized;
    const destSpace = new InnerSpace_V1({
        ...DEFAULT_INNER_SPACE_DATA_V1,
        name: 'dest',
        uuid: 'dest_uuid',
        description: 'receiver (domain provider) durable space',
    });
    await destSpace.initialized;
    const senderCoordinator = new SyncSagaCoordinator();
    const receiverCoordinator = new SyncSagaCoordinator();
    async function newTestIbGib_stone({ ib = 'test', data }) {
        const stone = await Factory_V1.stone({
            parentPrimitiveIb: ib.split(' ').at(0) ?? 'test',
            ib,
            data,
            uuid: true,
        });
        return stone;
    }
    async function newTestPeer() {
        const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
        await peer.initialized;
        await peer.initializeOpts({
            sagaId: '',
            localMetaspace: metaspace,
            localSpace: sourceSpace,
            receiverSpace: destSpace,
            receiverCoordinator,
            receiverMetaspace: metaspace,
        });
        return peer;
    }
    const keystoneSvc = new KeystoneService_V1();
    // #endregion Init/Setup
    let senderIdentity;
    // Create senderIdentity genesis (I^Itjp) in sourceSpace
    senderIdentity = await keystoneSvc.genesis({
        masterSecret: SENDER_SECRET,
        configs: [SENDER_IDENTITY_SYNC_POOL_CONFIG],
        metaspace,
        space: sourceSpace,
    });
    // post the senderIdentity to receiver
    await metaspace.put({ ibGib: senderIdentity, space: destSpace });
    await metaspace.registerNewIbGib({ ibGib: senderIdentity, space: destSpace });
    // Execute sync
    let syncError = null;
    let xStone;
    let xStoneAddr;
    let peer;
    try {
        xStone = await newTestIbGib_stone({ ib: 'test' });
        xStoneAddr = getIbGibAddr({ ibGib: xStone });
        await metaspace.put({ ibGib: xStone, space: sourceSpace });
        await metaspace.registerNewIbGib({ ibGib: xStone, space: sourceSpace });
        peer = await newTestPeer();
        const syncSaga = await senderCoordinator.sync({
            domainIbGibs: [xStone],
            senderIdentity,
            fnSenderSecret: async () => SENDER_SECRET,
            peer,
            localSpace: sourceSpace,
            metaspace,
            conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
        });
        await syncSaga.done;
    }
    catch (error) {
        syncError = error;
        if (logalot) {
            console.log(`${lc} Captured expected downstream/coordinator error: ${extractErrorMsg(error)}`);
        }
    }
    // #region Step 3: Check states
    await ifWe(sir, 'does not throw connection-specific errors', async () => {
        const errorMsg = syncError ? extractErrorMsg(syncError) : '';
        // If it throws, the error should NOT be related to establishment or connection.
        // It's expected to throw downstream in executeSagaLoop or continueSync due to missing context authentication/turn signing.
        iReckon(sir, errorMsg.includes('establish') || errorMsg.includes('connect')).asTo('error is NOT related to establish or connect').isGonnaBeFalsy();
    });
    await ifWe(sir, 'session identity S connect pool is not depleted (innerspace no-op asymmetry)', async () => {
        // Resolve latest evolved I1
        const newSenderIdentityAddr = await metaspace.getLatestAddr({
            ibGib: senderIdentity,
            space: sourceSpace,
        });
        if (!newSenderIdentityAddr) {
            throw new Error(`newSenderIdentity not found`);
        }
        const newSenderIdentity = await getIdentity_throwIfUndefined({
            addr: newSenderIdentityAddr,
            metaspace,
            space: sourceSpace,
        });
        const sessionIdentityTjpAddr = newSenderIdentity.data.proofs
            .find(p => p.claim.verb === KEYSTONE_VERB_SYNC)?.claim.target;
        if (!sessionIdentityTjpAddr) {
            throw new Error(`sessionIdentityTjpAddr not found`);
        }
        const sessionIdentity = await getIdentity_throwIfUndefined({
            addr: sessionIdentityTjpAddr,
            metaspace,
            space: sourceSpace,
        });
        // The connect pool should exist and have all challenges remaining (no-op innerspace connect)
        const connectPool = sessionIdentity.data.challengePools?.find(p => p.id === POOL_ID_CONNECT);
        iReckon(sir, connectPool).asTo('connect pool exists on S').isGonnaBeTruthy();
        const remainingChallenges = Object.keys(connectPool?.challenges ?? {});
        iReckon(sir, remainingChallenges.length).asTo('connect pool has all challenges').willEqual(20);
    });
    // #endregion Step 3: Check states
});
//# sourceMappingURL=sync-withid.connect.respec.mjs.map