/**
 * @module subject respec
 *
 * we gotta test our subject
 */
import * as pathUtils from 'path';
import { firstOfEach, ifWe, iReckon, respecfully } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
const maam = `[${import.meta.url}]`, sir = maam;
import { delay, } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { GIB, ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
import { Factory_V1 } from '@ibgib/ts-gib/dist/V1/factory.mjs';
import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
import { newupSubject } from './subject-helper.mjs';
import { fnObs } from '../observer/observer-helper.mjs';
import { getErrorIbGib } from '../../error/error-helper.mjs';
/**
 * for verbose logging. import this.
 */
const logalot = GLOBAL_LOG_A_LOT; // change this when you want to turn off verbose logging
const lcFile = `[${pathUtils.basename(import.meta.url)}]`;
await respecfully(sir, `integration`, async () => {
    await respecfully(sir, `next section`, async () => {
        const TEST_GIB = { ib: 'test', gib: GIB };
        const testPrimitives = [ROOT, TEST_GIB];
        const testProducer = await newupSubject();
        let nextProduced = undefined;
        let errorProduced = undefined;
        let completeTriggered = undefined;
        /**
         * normally this fnObs call would be inside the subscribe more like an
         * anonymous lambda.
         */
        const testConsumer = fnObs({
            next: async (output) => {
                nextProduced = output;
            },
            error: async (err) => {
                errorProduced = err;
            },
            complete: async () => {
                completeTriggered = true;
            },
        });
        firstOfEach(sir, async () => {
            nextProduced = undefined;
            errorProduced = undefined;
            completeTriggered = undefined;
        });
        const subscription = await testProducer.subscribe(testConsumer);
        for (let i = 0; i < testPrimitives.length; i++) {
            await ifWe(sir, 'next', async () => {
                const ibGib = testPrimitives[i];
                iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
                iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
                await testProducer.next(ibGib);
                iReckon(sir, nextProduced).asTo('nextProduced2').isGonnaBeTruthy();
                iReckon(sir, errorProduced).asTo('errorProduced2').isGonnaBeUndefined();
                iReckon(sir, completeTriggered).asTo('completeTriggered2').isGonnaBeUndefined();
                iReckon(sir, nextProduced).isGonnaBe(ibGib);
            });
        }
        await ifWe(sir, 'unsubscribe', async () => {
            const unsubscribed_beforeUnsubscribing = await subscription.unsubscribed();
            iReckon(sir, unsubscribed_beforeUnsubscribing).asTo('before').isGonnaBeFalse();
            await subscription.unsubscribe();
            const unsubscribed_afterUnsubscribing = await subscription.unsubscribed();
            iReckon(sir, unsubscribed_afterUnsubscribing).asTo('after').isGonnaBeTrue();
        });
        await ifWe(sir, 'confirm unsubscribe', async () => {
            await testProducer.next(ROOT);
            iReckon(sir, nextProduced).asTo('nextProduced').isGonnaBeUndefined();
            iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
            iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
        });
    });
    await respecfully(sir, `error section`, async () => {
        // same as above but do an error after the next and before unsubscribe
        const TEST_ERROR_STRING = 'problem yo d6f802916b424168bea8ab8659fde742';
        const TEST_ERROR_OBJECT_MSG = 'error in an object 00e270c4de3d4d6991d83585c6e8b08f';
        const TEST_ERROR_IBGIB_RAW_MSG = 'error in an ibgib 0cffc88c16ed48889be22529a9d6f1f5';
        const TEST_ERROR_OBJECT = new Error(TEST_ERROR_OBJECT_MSG);
        const TEST_ERROR_IBGIB = await getErrorIbGib({ rawMsg: TEST_ERROR_IBGIB_RAW_MSG });
        /**
         * we'll test each of these, because you can pass in either a string, object
         * or error ibgib to the `subject.error` function.
         */
        const TEST_ERROR_VALUES = [
            ['string', TEST_ERROR_STRING],
            ['object', TEST_ERROR_OBJECT],
            ['ibgib', TEST_ERROR_IBGIB]
        ];
        for (let i = 0; i < TEST_ERROR_VALUES.length; i++) {
            const [testErrorLabel, testError] = TEST_ERROR_VALUES[i];
            await respecfully(sir, `next, error(${testErrorLabel}), unsubscribe`, async () => {
                const TEST_GIB = { ib: 'test', gib: GIB };
                const testPrimitives = [ROOT, TEST_GIB];
                const testProducer = await newupSubject();
                let nextProduced = undefined;
                let errorProduced = undefined;
                let completeTriggered = undefined;
                /**
                 * normally this fnObs call would be inside the subscribe more like an
                 * anonymous lambda.
                 */
                const testConsumer = fnObs({
                    next: async (output) => {
                        nextProduced = output;
                    },
                    error: async (err) => {
                        errorProduced = err;
                    },
                    complete: async () => {
                        completeTriggered = true;
                    },
                });
                firstOfEach(sir, async () => {
                    nextProduced = undefined;
                    errorProduced = undefined;
                    completeTriggered = undefined;
                });
                const subscription = await testProducer.subscribe(testConsumer);
                for (let i = 0; i < testPrimitives.length; i++) {
                    await ifWe(sir, 'next', async () => {
                        const ibGib = testPrimitives[i];
                        iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                        iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
                        iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
                        await testProducer.next(ibGib);
                        iReckon(sir, nextProduced).asTo('nextProduced2').isGonnaBeTruthy();
                        iReckon(sir, errorProduced).asTo('errorProduced2').isGonnaBeUndefined();
                        iReckon(sir, completeTriggered).asTo('completeTriggered2').isGonnaBeUndefined();
                        iReckon(sir, nextProduced).isGonnaBe(ibGib);
                        iReckon(sir, testProducer.isErrored).isGonnaBeFalse();
                    });
                }
                await ifWe(sir, 'error', async () => {
                    await testProducer.error(testError);
                    iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                    iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeTruthy();
                    iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
                    iReckon(sir, testProducer.isErrored).isGonnaBeTrue();
                    iReckon(sir, testProducer.isComplete).isGonnaBeFalse();
                    iReckon(sir, testProducer.isCompleteOrErrored).isGonnaBeTrue();
                });
                await ifWe(sir, `next after error does not produce`, async () => {
                    iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                    await testProducer.next(ROOT);
                    // should still be undefined
                    iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                });
                await ifWe(sir, 'unsubscribe', async () => {
                    const unsubscribed_beforeUnsubscribing = await subscription.unsubscribed();
                    iReckon(sir, unsubscribed_beforeUnsubscribing).asTo('before').isGonnaBeFalse();
                    await subscription.unsubscribe();
                    const unsubscribed_afterUnsubscribing = await subscription.unsubscribed();
                    iReckon(sir, unsubscribed_afterUnsubscribing).asTo('after').isGonnaBeTrue();
                });
                await ifWe(sir, 'confirm unsubscribe', async () => {
                    await testProducer.next(ROOT);
                    iReckon(sir, nextProduced).asTo('nextProduced').isGonnaBeUndefined();
                    iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
                    iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
                });
            });
        }
    });
    await respecfully(sir, `complete section`, async () => {
        const TEST_GIB = { ib: 'test', gib: GIB };
        const testPrimitives = [ROOT, TEST_GIB];
        const testProducer = await newupSubject();
        let nextProduced = undefined;
        let errorProduced = undefined;
        let completeTriggered = undefined;
        /**
         * normally this fnObs call would be inside the subscribe more like an
         * anonymous lambda.
         */
        const testConsumer = fnObs({
            next: async (output) => {
                nextProduced = output;
            },
            error: async (err) => {
                errorProduced = err;
            },
            complete: async () => {
                completeTriggered = true;
            },
        });
        firstOfEach(sir, async () => {
            nextProduced = undefined;
            errorProduced = undefined;
            completeTriggered = undefined;
        });
        const subscription = await testProducer.subscribe(testConsumer);
        for (let i = 0; i < testPrimitives.length; i++) {
            await ifWe(sir, 'next', async () => {
                const ibGib = testPrimitives[i];
                iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
                iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
                iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeUndefined();
                await testProducer.next(ibGib);
                iReckon(sir, nextProduced).asTo('nextProduced2').isGonnaBeTruthy();
                iReckon(sir, errorProduced).asTo('errorProduced2').isGonnaBeUndefined();
                iReckon(sir, completeTriggered).asTo('completeTriggered2').isGonnaBeUndefined();
                iReckon(sir, nextProduced).isGonnaBe(ibGib);
                iReckon(sir, testProducer.isErrored).isGonnaBeFalse();
            });
        }
        await ifWe(sir, 'complete', async () => {
            await testProducer.complete();
            iReckon(sir, nextProduced).asTo('nextProduce').isGonnaBeUndefined();
            iReckon(sir, errorProduced).asTo('errorProduced').isGonnaBeUndefined();
            iReckon(sir, completeTriggered).asTo('completeTriggered').isGonnaBeTrue();
            iReckon(sir, testProducer.isErrored).isGonnaBeFalse();
            iReckon(sir, testProducer.isComplete).isGonnaBeTrue();
            iReckon(sir, testProducer.isCompleteOrErrored).isGonnaBeTrue();
        });
        await ifWe(sir, 'unsubscribe', async () => {
            const unsubscribed_beforeUnsubscribing = await subscription.unsubscribed();
            iReckon(sir, unsubscribed_beforeUnsubscribing).asTo('before').isGonnaBeFalse();
            await subscription.unsubscribe();
            const unsubscribed_afterUnsubscribing = await subscription.unsubscribed();
            iReckon(sir, unsubscribed_afterUnsubscribing).asTo('after').isGonnaBeTrue();
        });
    });
});
await respecfully(sir, `replay`, async () => {
    const testPrimitives = Factory_V1.primitives({ ibs: [0, 1, 2, 3, 4].map(x => x.toString()) });
    const testProducer = await newupSubject({ replay: true });
    const allProduced_earlySubscriber = [];
    let errorProduced_earlySubscriber = undefined;
    let completeTriggered_earlySubscriber = false;
    const earlySubscriber = fnObs({
        next: async (output) => {
            allProduced_earlySubscriber.push(output);
        },
        error: async (err) => {
            errorProduced_earlySubscriber = err;
        },
        complete: async () => {
            completeTriggered_earlySubscriber = true;
        },
    });
    const allProduced_lateSubscriber = [];
    let errorProduced_lateSubscriber = undefined;
    let completeTriggered_lateSubscriber = false;
    const lateSubscriber = fnObs({
        next: async (output) => {
            allProduced_lateSubscriber.push(output);
        },
        error: async (err) => {
            errorProduced_lateSubscriber = err;
        },
        complete: async () => {
            completeTriggered_lateSubscriber = true;
        },
    });
    // ok we have to subscribers, neither of which are subscribed yet.  we are
    // going to subscribe the early one and then BEFORE subscribing the late
    // subscriber, we will publish the testPrimitives.
    const earlySubscription = await testProducer.subscribe(earlySubscriber);
    for (let i = 0; i < testPrimitives.length; i++) {
        const testPrimitive = testPrimitives[i];
        await testProducer.next(testPrimitive); // published to earlySubscriber per call to next
    }
    await ifWe(sir, 'test replay earlySubscriber', async () => {
        iReckon(sir, allProduced_earlySubscriber.length).asTo('early length 1').isGonnaBe(testPrimitives.length);
    });
    await ifWe(sir, 'test replay lateSubscriber', async () => {
        // before subscribing should be 0
        iReckon(sir, allProduced_lateSubscriber.length).asTo('late length before subscribe').isGonnaBe(0);
        // subscribe should trigger replay
        const lateSubscription = await testProducer.subscribe(lateSubscriber);
        // have to have slight relatively arbitrary delay because payload replay
        // is spun off ("parallel"). if this test fails, it could be because it
        // doesn't wait long enough. I can get in-between failing results at
        // around 5 ms delay.
        await delay(50);
        iReckon(sir, allProduced_lateSubscriber.length).asTo('late length after subscribe and delay').isGonnaBe(testPrimitives.length);
    });
    await ifWe(sir, 'both early and late subscribers should get subsequent payloads', async () => {
        await testProducer.next(ROOT);
        iReckon(sir, allProduced_earlySubscriber.length).asTo('early length').isGonnaBe(testPrimitives.length + 1);
        iReckon(sir, allProduced_lateSubscriber.length).asTo('late length').isGonnaBe(testPrimitives.length + 1);
        await testProducer.next(ROOT);
        iReckon(sir, allProduced_earlySubscriber.length).asTo('early length 2').isGonnaBe(testPrimitives.length + 2);
        iReckon(sir, allProduced_lateSubscriber.length).asTo('late length 2').isGonnaBe(testPrimitives.length + 2);
    });
    // todo: more replay test cases, including after error/complete a subscriber should still get all payloads. error should also get the final error published.
});
//# sourceMappingURL=subject.respec.mjs.map