/**
 * @vitest-environment happy-dom
 */
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook } from "@testing-library/react";
import { useCartSession } from "./useCartSession";

const mockUseConvexAuth = vi.fn();
vi.mock("convex/react", async (importOriginal) => {
  const actual = await importOriginal<typeof import("convex/react")>();
  return {
    ...actual,
    useConvexAuth: () => mockUseConvexAuth(),
  };
});

const mockGetGuestSessionId = vi.fn();
const mockSetGuestSessionCookie = vi.fn();
const mockGenerateGuestSessionId = vi.fn();
vi.mock("./cookie", () => ({
  getGuestSessionId: () => mockGetGuestSessionId(),
  setGuestSessionCookie: (id: string) => mockSetGuestSessionCookie(id),
  generateGuestSessionId: () => mockGenerateGuestSessionId(),
}));

describe("useCartSession", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockGenerateGuestSessionId.mockReturnValue("generated-uuid-123");
    mockUseConvexAuth.mockReturnValue({ isLoading: false, isAuthenticated: false });
  });

  it("returns authenticated session when loaded and signed in", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: false, isAuthenticated: true });
    const { result } = renderHook(() => useCartSession());
    expect(result.current).toEqual({ sessionId: undefined, isGuest: false });
    expect(mockGetGuestSessionId).not.toHaveBeenCalled();
  });

  it("returns guest session with cookie value when not signed in and cookie present", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: false, isAuthenticated: false });
    mockGetGuestSessionId.mockReturnValue("cookie-uuid-456");
    const { result } = renderHook(() => useCartSession());
    expect(result.current).toEqual({
      sessionId: "cookie-uuid-456",
      isGuest: true,
    });
    expect(mockGetGuestSessionId).toHaveBeenCalled();
    expect(mockSetGuestSessionCookie).not.toHaveBeenCalled();
    expect(mockGenerateGuestSessionId).not.toHaveBeenCalled();
  });

  it("returns guest session and sets cookie when not signed in and cookie missing", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: false, isAuthenticated: false });
    mockGetGuestSessionId.mockReturnValue(null);
    const { result } = renderHook(() => useCartSession());
    expect(result.current).toEqual({
      sessionId: "generated-uuid-123",
      isGuest: true,
    });
    expect(mockGetGuestSessionId).toHaveBeenCalled();
    expect(mockGenerateGuestSessionId).toHaveBeenCalled();
    expect(mockSetGuestSessionCookie).toHaveBeenCalledWith("generated-uuid-123");
  });

  it("treats not-loaded auth as guest and uses cookie when present", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: true, isAuthenticated: false });
    mockGetGuestSessionId.mockReturnValue("existing-guest-id");
    const { result } = renderHook(() => useCartSession());
    expect(result.current).toEqual({
      sessionId: "existing-guest-id",
      isGuest: true,
    });
    expect(mockSetGuestSessionCookie).not.toHaveBeenCalled();
  });

  it("treats not-loaded auth as guest and creates session when cookie missing", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: true, isAuthenticated: false });
    mockGetGuestSessionId.mockReturnValue(null);
    const { result } = renderHook(() => useCartSession());
    expect(result.current).toEqual({
      sessionId: "generated-uuid-123",
      isGuest: true,
    });
    expect(mockSetGuestSessionCookie).toHaveBeenCalledWith("generated-uuid-123");
  });

  it("returns authenticated only when both isLoaded and isSignedIn are true", () => {
    mockUseConvexAuth.mockReturnValue({ isLoading: false, isAuthenticated: false });
    mockGetGuestSessionId.mockReturnValue("guest-id");
    const { result } = renderHook(() => useCartSession());
    expect(result.current.isGuest).toBe(true);
    expect(result.current.sessionId).toBe("guest-id");
  });
});
