import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderHook } from "@testing-library/react";

let esInstances: {
  url: string;
  onmessage?: (e: MessageEvent) => void;
  onerror?: () => void;
  onopen?: () => void;
  close: ReturnType<typeof vi.fn>;
}[] = [];

class MockEventSource {
  url: string;
  onmessage: ((e: MessageEvent) => void) | undefined;
  onerror: (() => void) | undefined;
  onopen: (() => void) | undefined;
  close = vi.fn();

  constructor(url: string) {
    this.url = url;
    esInstances.push(this);
  }
}

vi.stubGlobal("EventSource", MockEventSource);

vi.mock("swr", () => ({
  default: vi.fn().mockReturnValue({
    data: {
      roomId: "ROOM01",
      userCount: 2,
      match: null,
      matchType: null,
      matchLikes: 0,
      runnerUps: [],
      likeCounts: {},
      swipeCounts: {},
      restaurants: [],
      creatorId: "user-1",
      locked: false,
      users: ["user-1", "user-2"],
      userProfiles: {},
      scene: "eat",
    },
    error: null,
    isLoading: false,
    mutate: vi.fn(),
  }),
}));

import { useRoomPolling } from "./useRoomPolling";

beforeEach(() => {
  esInstances = [];
});

afterEach(() => {
  vi.clearAllMocks();
});

describe("useRoomPolling", () => {
  it("returns room data from SWR", () => {
    const { result } = renderHook(() => useRoomPolling("ROOM01", "user-1"));

    expect(result.current.userCount).toBe(2);
    expect(result.current.users).toEqual(["user-1", "user-2"]);
    expect(result.current.scene).toBe("eat");
  });

  it("creates EventSource connection", () => {
    renderHook(() => useRoomPolling("ROOM01", "user-1"));
    expect(esInstances.length).toBeGreaterThan(0);
    expect(esInstances[0].url).toContain("/api/room/ROOM01/events?userId=user-1");
  });

  it("does not create EventSource when userId is missing", () => {
    renderHook(() => useRoomPolling("ROOM01"));
    expect(esInstances.length).toBe(0);
  });

  it("returns defaults when no roomId", () => {
    const { result } = renderHook(() => useRoomPolling(undefined, "user-1"));
    expect(result.current.userCount).toBe(2);
  });

  it("returns notFound from error state", async () => {
    const useSWR = vi.mocked((await import("swr")).default);
    useSWR.mockReturnValue({
      data: undefined,
      error: new Error("NOT_FOUND"),
      isLoading: false,
      mutate: vi.fn(),
    } as never);

    const { result } = renderHook(() => useRoomPolling("ROOM01", "user-1"));
    expect(result.current.notFound).toBe(true);
  });

  it("cleans up EventSource on unmount", () => {
    const { unmount } = renderHook(() => useRoomPolling("ROOM01", "user-1"));
    const es = esInstances[esInstances.length - 1];
    unmount();
    expect(es.close).toHaveBeenCalled();
  });
});
