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

function ThemeConsumer(): React.JSX.Element {
  const { colorMode, toggleColorMode } = useThemeMode();
  return (
    <div>
      <span data-testid="color-mode">{colorMode}</span>
      <button type="button" onClick={toggleColorMode}>
        Toggle
      </button>
    </div>
  );
}

function renderWithProvider(): void {
  render(
    <ThemeProvider>
      <ThemeConsumer />
    </ThemeProvider>,
  );
}

describe("ThemeProvider", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
    localStorage.clear();
    Object.defineProperty(window, "matchMedia", {
      configurable: true,
      writable: true,
      value: vi.fn().mockReturnValue({
        matches: false,
        addEventListener: vi.fn(),
        removeEventListener: vi.fn(),
      }),
    });
  });

  it("uses the saved theme from localStorage when present", () => {
    localStorage.setItem("bangui_theme", "dark");
    renderWithProvider();
    expect(screen.getByTestId("color-mode")).toHaveTextContent("dark");
  });

  it("falls back to the OS preference when no explicit theme is saved", () => {
    Object.defineProperty(window, "matchMedia", {
      configurable: true,
      writable: true,
      value: vi.fn().mockReturnValue({
        matches: true,
        addEventListener: vi.fn(),
        removeEventListener: vi.fn(),
      }),
    });
    renderWithProvider();
    expect(screen.getByTestId("color-mode")).toHaveTextContent("dark");
  });

  it("persists the user selection to localStorage when toggled", async () => {
    renderWithProvider();
    expect(screen.getByTestId("color-mode")).toHaveTextContent("light");

    await screen.getByRole("button", { name: /toggle/i }).click();
    expect(screen.getByTestId("color-mode")).toHaveTextContent("dark");
    expect(localStorage.getItem("bangui_theme")).toBe("dark");
  });
});
