/* @vitest-environment jsdom */

import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { CHARACTERS, createCharacterCatalog } from "@/data/constants/character";

const mocks = vi.hoisted(() => ({
  replace: vi.fn(),
  catalog: null as unknown as ReturnType<
    typeof import("@/providers/character-catalog-provider").useCharacterCatalog
  >,
}));

vi.mock("next/navigation", () => ({
  useRouter: () => ({ replace: mocks.replace }),
}));

vi.mock("@/providers/character-catalog-provider", () => ({
  useCharacterCatalog: () => mocks.catalog,
}));

import { CharacterRouteBoundary } from "../character-route-boundary";

describe("CharacterRouteBoundary", () => {
  let root: Root;
  let container: HTMLDivElement;

  beforeEach(() => {
    container = document.createElement("div");
    document.body.append(container);
    root = createRoot(container);
    mocks.replace.mockReset();
  });

  afterEach(() => {
    act(() => root.unmount());
    container.remove();
  });

  it("waits for the catalog before mounting character content", () => {
    mocks.catalog = catalogValue("loading", CHARACTERS);
    act(() => {
      root.render(
        <CharacterRouteBoundary character={CHARACTERS[0]}>
          <span>Chat actor mounted</span>
        </CharacterRouteBoundary>,
      );
    });

    expect(container.textContent).not.toContain("Chat actor mounted");
    expect(container.querySelector('[role="status"]')).not.toBeNull();
  });

  it("redirects an unavailable character to the default splash", () => {
    mocks.catalog = catalogValue("ready", [CHARACTERS[0]]);
    act(() => {
      root.render(
        <CharacterRouteBoundary character={CHARACTERS[1]}>
          <span>Maya</span>
        </CharacterRouteBoundary>,
      );
    });

    expect(mocks.replace).toHaveBeenCalledWith("/characters/elio/splash");
    expect(container.textContent).not.toContain("Maya");
  });
});

function catalogValue(
  status: "loading" | "ready" | "refreshing",
  characters: typeof CHARACTERS,
) {
  const catalog = createCharacterCatalog(characters);
  return {
    ...catalog,
    status,
    defaultCharacter: CHARACTERS[0],
    isFallback: false,
    refresh: async () => undefined,
  };
}
