/* @vitest-environment jsdom */

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

import type { AuthPanelMode, LoginStatus } from "@/data/dto/auth";

vi.mock("@/stores/auth/auth-machine", async () => {
  const { setup } = await import("xstate");
  const initialState = {
    authPanelMode: "facebook" as AuthPanelMode,
    errorMessage: null as string | null,
    loginStatus: "notLoggedIn" as LoginStatus,
    hasInitialized: false as boolean,
  };
  const authMachine = setup({
    types: {
      context: {} as typeof initialState,
      events: {} as { type: "AuthNoop" },
    },
  }).createMachine({
    initial: "idle",
    context: {
      ...initialState,
      loginStatus: "facebook",
      hasInitialized: true,
    },
    states: { idle: {} },
  });

  return { authMachine, initialState };
});

import {
  AuthProvider,
  useAuthState,
} from "@/stores/auth/auth-context";

function AuthStateProbe() {
  const state = useAuthState();
  const isLoading = !state.hasInitialized || state.isLoading;

  return <button disabled={isLoading}>{isLoading ? "Loading" : "Ready"}</button>;
}

function TestTree() {
  return (
    <AuthProvider>
      <AuthStateProbe />
    </AuthProvider>
  );
}

describe("AuthContext hydration", () => {
  let root: Root | null = null;

  afterEach(async () => {
    if (root) {
      await act(async () => root?.unmount());
      root = null;
    }
    document.body.innerHTML = "";
  });

  it("uses the server auth snapshot until hydration completes", async () => {
    const serverHtml = renderToString(<TestTree />);
    const container = document.createElement("div");
    const hydrationErrors: unknown[] = [];
    container.innerHTML = serverHtml;
    document.body.append(container);

    expect(container.querySelector("button")?.disabled).toBe(true);
    expect(container.textContent).toBe("Loading");

    await act(async () => {
      root = hydrateRoot(container, <TestTree />, {
        onRecoverableError: (error) => hydrationErrors.push(error),
      });
    });

    expect(hydrationErrors).toEqual([]);
    expect(container.querySelector("button")?.disabled).toBe(false);
    expect(container.textContent).toBe("Ready");
  });
});
