import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, act } from "@testing-library/react";
import { ThemeProvider, useTheme } from "./ThemeProvider";

function ThemeConsumer(): React.JSX.Element {
  const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme();
  return (
    <div>
      <span data-testid="theme">{theme}</span>
      <span data-testid="resolved">{resolvedTheme}</span>
      <button
        onClick={() => {
          setTheme("light");
        }}
      >
        Set Light
      </button>
      <button
        onClick={() => {
          setTheme("dark");
        }}
      >
        Set Dark
      </button>
      <button
        onClick={() => {
          toggleTheme();
        }}
      >
        Toggle
      </button>
    </div>
  );
}

describe("ThemeProvider", (): void => {
  let mockMatchMedia: ReturnType<typeof vi.fn>;

  beforeEach((): void => {
    localStorage.clear();
    document.documentElement.classList.remove("light", "dark");

    mockMatchMedia = vi.fn().mockReturnValue({
      matches: false,
      addEventListener: vi.fn(),
      removeEventListener: vi.fn(),
    });
    Object.defineProperty(window, "matchMedia", {
      writable: true,
      value: mockMatchMedia,
    });
  });

  afterEach((): void => {
    vi.restoreAllMocks();
  });

  it("should use 'mosaic-theme' as storage key", (): void => {
    localStorage.setItem("mosaic-theme", "light");

    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    );

    expect(screen.getByTestId("theme")).toHaveTextContent("light");
  });

  it("should NOT read from old 'jarvis-theme' storage key", (): void => {
    localStorage.setItem("jarvis-theme", "light");

    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    );

    // Should default to system, not read from jarvis-theme
    expect(screen.getByTestId("theme")).toHaveTextContent("system");
  });

  it("should store theme under 'mosaic-theme' key", (): void => {
    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    );

    act(() => {
      screen.getByText("Set Light").click();
    });

    expect(localStorage.getItem("mosaic-theme")).toBe("light");
    expect(localStorage.getItem("jarvis-theme")).toBeNull();
  });

  it("should render children", (): void => {
    render(
      <ThemeProvider>
        <div data-testid="child">Hello</div>
      </ThemeProvider>
    );

    expect(screen.getByTestId("child")).toBeInTheDocument();
  });

  it("should throw when useTheme is used outside provider", (): void => {
    // Suppress console.error for expected error
    const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {
      // Intentionally empty
    });

    expect(() => {
      render(<ThemeConsumer />);
    }).toThrow("useTheme must be used within a ThemeProvider");

    consoleSpy.mockRestore();
  });
});
