import { describe, expect, it } from "vitest";
import { createActor, fromCallback, waitFor } from "xstate";

import type { UiMessage } from "@/data/dto/chat";
import type { ChatEvent } from "@/stores/chat/chat-events";
import { chatMachine } from "@/stores/chat/chat-machine";

import { createTestChatMachine } from "./chat-machine.test-utils";

describe("chat history flow", () => {
  it("enters user ready after history is loaded", async () => {
    const actor = createActor(createTestChatMachine()).start();

    actor.send({ type: "ChatUserLogin", token: "token" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ userSession: "ready" }),
    );

    const snapshot = actor.getSnapshot();
    expect(snapshot.context.historyLoaded).toBe(true);

    actor.stop();
  });

  it("renders local history before network history sync finishes", async () => {
    let resolveNetwork!: () => void;
    const networkReleased = new Promise<void>((resolve) => {
      resolveNetwork = resolve;
    });
    const localMessage: UiMessage = {
      id: "local-msg",
      content: "cached local message",
      isFromAI: true,
      date: "2026-07-02",
    };
    const networkMessage: UiMessage = {
      id: "network-msg",
      content: "fresh network message",
      isFromAI: true,
      date: "2026-07-02",
    };
    const machine = chatMachine.provide({
      actors: {
        loadHistory: fromCallback<ChatEvent>(({ sendBack }) => {
          sendBack({
            type: "ChatLocalHistoryLoaded",
            output: {
              messages: [localMessage],
              localCount: 1,
            },
          });
          void networkReleased.then(() => {
            sendBack({
              type: "ChatNetworkHistoryLoaded",
              output: {
                messages: [networkMessage],
                localOverwritten: true,
                localCount: 1,
                networkCount: 1,
              },
            });
          });
          return () => undefined;
        }),
      },
    });
    const actor = createActor(machine).start();

    actor.send({ type: "ChatUserLogin", token: "token" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ userSession: "ready" }),
    );

    expect(actor.getSnapshot().context.messages).toMatchObject([
      { id: "local-msg", content: "cached local message" },
    ]);

    resolveNetwork();
    await waitFor(
      actor,
      (snapshot) => snapshot.context.messages[0]?.id === "network-msg",
    );

    expect(actor.getSnapshot().context.messages).toMatchObject([
      { id: "network-msg", content: "fresh network message" },
    ]);

    actor.stop();
  });
});
