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

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

describe("chat session flow", () => {
  it("initializes the conversation from the supplied character", () => {
    const actor = createActor(createTestChatMachine(), {
      input: {
        characterId: "maya-tan",
        emptyChatGreeting: "Hello from Maya",
      },
    }).start();

    expect(actor.getSnapshot().context).toMatchObject({
      characterId: "maya-tan",
      emptyChatGreeting: "Hello from Maya",
    });
    actor.stop();
  });

  it("keeps the active character greeting across login state changes", async () => {
    const actor = createActor(createTestChatMachine(), {
      input: {
        characterId: "maya-tan",
        emptyChatGreeting: "Hello from Maya",
      },
    }).start();

    actor.send({ type: "ChatUserLogin", token: "token" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ userSession: "ready" }),
    );
    expect(actor.getSnapshot().context.emptyChatGreeting).toBe(
      "Hello from Maya",
    );

    actor.send({ type: "ChatGuestLogin" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ guestSession: "ready" }),
    );
    expect(actor.getSnapshot().context.emptyChatGreeting).toBe(
      "Hello from Maya",
    );

    actor.stop();
  });

  it("keeps guest logout disabled and supports user to guest transition", async () => {
    const actor = createActor(createTestChatMachine(), {
      input: TEST_CHAT_MACHINE_INPUT,
    }).start();

    actor.send({ type: "ChatGuestLogin" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ guestSession: "ready" }),
    );

    actor.send({ type: "ChatLogout" });
    expect(actor.getSnapshot().matches({ guestSession: "ready" })).toBe(true);

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

    actor.send({ type: "ChatGuestLogin" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ guestSession: "ready" }),
    );

    actor.stop();
  });

  it("allows explicit logout from user session", async () => {
    const actor = createActor(createTestChatMachine(), {
      input: TEST_CHAT_MACHINE_INPUT,
    }).start();

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

    actor.send({ type: "ChatLogout" });
    expect(actor.getSnapshot().matches("idle")).toBe(true);

    actor.stop();
  });

  it("keeps a promotion separate from normal history", async () => {
    const actor = createActor(
      createTestChatMachine({
        historyMessages: [
          {
            displayId: "history-1",
            content: "Existing history",
            isFromAI: true,
            date: "2026-07-13",
          },
        ],
      }),
      { input: TEST_CHAT_MACHINE_INPUT },
    ).start();

    actor.send({ type: "ChatUserLogin", token: "token" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ userSession: "ready" }),
    );
    actor.send({
      type: "ChatPromotionInjected",
      promotion: {
        characterId: "elio",
        promotionType: "voice",
        lockType: "voice_message",
        clientLockId: "promotion-1",
        createdAt: 1,
      },
    });

    const context = actor.getSnapshot().context;
    expect(context.messages).toHaveLength(1);
    expect(context.promotion?.message).toMatchObject({
      displayId: "promotion:promotion-1",
      locked: true,
      lockReason: "voice_message",
    });

    actor.stop();
  });

  it("switches to guest session when guest login arrives during user session", async () => {
    const actor = createActor(createTestChatMachine(), {
      input: TEST_CHAT_MACHINE_INPUT,
    }).start();

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

    actor.send({ type: "ChatGuestLogin" });
    await waitFor(actor, (snapshot) =>
      snapshot.matches({ guestSession: "ready" }),
    );

    actor.stop();
  });

  it("ignores repeated user login while an authenticated user session is active", async () => {
    const actor = createActor(createTestChatMachine(), {
      input: TEST_CHAT_MACHINE_INPUT,
    }).start();

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

    actor.send({ type: "ChatSendMessage", content: "keep this message" });
    await waitFor(
      actor,
      (snapshot) => snapshot.context.messages.length === 1,
    );

    actor.send({ type: "ChatUserLogin", token: "another-token" });

    expect(actor.getSnapshot().matches({ userSession: "ready" })).toBe(true);
    expect(actor.getSnapshot().context.messages).toMatchObject([
      { content: "keep this message", isFromAI: false },
    ]);

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