import { describe, it, expect } from "@jest/globals";
import { AnyValue } from "../channels/any_value.js";
import { EphemeralValue } from "../channels/ephemeral_value.js";
import { LastValue } from "../channels/last_value.js";
import { EmptyChannelError, InvalidUpdateError } from "../errors.js";
import { Topic } from "../channels/topic.js";
import { BinaryOperatorAggregate } from "../channels/binop.js";
describe("LastValue", () => {
    it("should handle last value correctly", () => {
        const channel = new LastValue();
        expect(() => {
            channel.get();
        }).toThrow(EmptyChannelError);
        expect(() => {
            channel.update([5, 6]);
        }).toThrow(InvalidUpdateError);
        channel.update([3]);
        expect(channel.get()).toBe(3);
        channel.update([4]);
        expect(channel.get()).toBe(4);
    });
    it("should handle restoring from checkpoint correctly", () => {
        // call `.update()` to add a value to the channel
        const channel = new LastValue();
        channel.update([100]);
        const checkpoint = channel.checkpoint();
        const restoredChannel = new LastValue();
        const channel2 = restoredChannel.fromCheckpoint(checkpoint);
        expect(channel2.get()).toBe(100);
    });
});
describe("Topic", () => {
    const channel = new Topic();
    it("should handle updates and get operations", () => {
        channel.update(["a", "b"]);
        expect(channel.get()).toEqual(["a", "b"]);
        channel.update([["c", "d"], "d"]);
        expect(channel.get()).toEqual(["c", "d", "d"]);
        channel.update([]);
        expect(channel.get()).toEqual([]);
        channel.update(["e"]);
        expect(channel.get()).toEqual(["e"]);
    });
    it("should create and use a checkpoint", () => {
        const checkpoint = channel.checkpoint();
        const newChannel = new Topic().fromCheckpoint(checkpoint);
        expect(newChannel.get()).toEqual(["e"]);
    });
});
describe("Topic with unique: true", () => {
    const channel = new Topic({ unique: true });
    it("should de-dupe updates and get the last unique value", () => {
        channel.update(["a", "b"]);
        expect(channel.get()).toEqual(["a", "b"]);
        channel.update(["b", ["c", "d"], "d"]);
        expect(channel.get()).toEqual(["c", "d"]);
        channel.update([]);
        expect(channel.get()).toEqual([]);
        channel.update(["e"]);
        expect(channel.get()).toEqual(["e"]);
    });
    it("should de-dupe from checkpoint", () => {
        const checkpoint = channel.checkpoint();
        const newChannel = new Topic({ unique: true }).fromCheckpoint(checkpoint);
        expect(newChannel.get()).toEqual(["e"]);
        newChannel.update(["d", "f"]);
        expect(newChannel.get()).toEqual(["f"]);
    });
});
describe("Topic with accumulate: true", () => {
    const channel = new Topic({ accumulate: true });
    it("should accumulate updates and get operations", () => {
        channel.update(["a", "b"]);
        expect(channel.get()).toEqual(["a", "b"]);
        channel.update(["b", ["c", "d"], "d"]);
        expect(channel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
        channel.update([]);
        expect(channel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
    });
    it("should create and use a checkpoint", () => {
        const checkpoint = channel.checkpoint();
        const newChannel = new Topic({ accumulate: true }).fromCheckpoint(checkpoint);
        expect(newChannel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
        newChannel.update(["e"]);
        expect(newChannel.get()).toEqual(["a", "b", "b", "c", "d", "d", "e"]);
    });
});
describe("Topic with accumulate and unique: true", () => {
    const channel = new Topic({ unique: true, accumulate: true });
    it("should handle unique and accumulate updates and get operations", () => {
        channel.update(["a", "b"]);
        expect(channel.get()).toEqual(["a", "b"]);
        channel.update(["b", ["c", "d"], "d"]);
        expect(channel.get()).toEqual(["a", "b", "c", "d"]);
        channel.update([]);
        expect(channel.get()).toEqual(["a", "b", "c", "d"]);
    });
    it("should create and use a checkpoint", () => {
        const checkpoint = channel.checkpoint();
        const newChannel = new Topic({
            unique: true,
            accumulate: true,
        }).fromCheckpoint(checkpoint);
        expect(newChannel.get()).toEqual(["a", "b", "c", "d"]);
        newChannel.update(["d", "e"]);
        expect(newChannel.get()).toEqual(["a", "b", "c", "d", "e"]);
    });
});
describe("BinaryOperatorAggregate", () => {
    it("should handle binary operator aggregation correctly", () => {
        const channel = new BinaryOperatorAggregate((a, b) => a + b, () => 0);
        expect(channel.get()).toBe(0);
        channel.update([1, 2, 3]);
        expect(channel.get()).toBe(6);
        channel.update([4]);
        expect(channel.get()).toBe(10);
    });
    it("should handle checkpointing correctly", () => {
        const channel = new BinaryOperatorAggregate((a, b) => a + b, () => 0);
        channel.update([1, 2, 3]);
        channel.update([4]);
        const checkpoint = channel.checkpoint();
        const restoredChannel = new BinaryOperatorAggregate((a, b) => a + b, () => 10);
        const channel2 = restoredChannel.fromCheckpoint(checkpoint);
        expect(channel2.get()).toBe(10);
    });
});
describe("AnyValue", () => {
    it("should handle any value correctly", () => {
        const channel = new AnyValue();
        expect(() => {
            channel.get();
        }).toThrow(EmptyChannelError);
        channel.update([3]);
        expect(channel.get()).toBe(3);
        channel.update([4, 5]);
        expect(channel.get()).toBe(5);
    });
});
describe("EphemeralValue with gaurd: false", () => {
    it("should handle ephemeral value correctly", () => {
        const channel = new EphemeralValue(false);
        expect(() => {
            channel.get();
        }).toThrow(EmptyChannelError);
        channel.update([3]);
        expect(channel.get()).toBe(3);
        channel.update([4, 5]);
        expect(channel.get()).toBe(5);
    });
});
