import { render, screen, fireEvent, act } from "@testing-library/react";
import { expect, test, vi, afterEach } from "vitest";
import { RulesTab } from "./RulesTab";
import { CleanConfig } from "../types";

const mockConfig: CleanConfig = {
  strip_utms: true,
  fix_quotes: false,
  fix_newlines: true,
  play_sound: true,
  autostart: false,
  hotkey: "Alt+Shift+C",
  custom_params: [],
};

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

test("renders rule options and calls toggles", () => {
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  expect(screen.getByText("Strip tracking parameters")).toBeInTheDocument();
  expect(screen.getByText("Normalize typography")).toBeInTheDocument();
  expect(screen.getByText("Clean trailing newlines")).toBeInTheDocument();

  const checkboxes = screen.getAllByRole("checkbox");

  expect(checkboxes[0]).toBeChecked();
  expect(checkboxes[1]).not.toBeChecked();
  expect(checkboxes[2]).toBeChecked();

  fireEvent.click(checkboxes[1]);

  expect(onUpdateConfig).toHaveBeenCalledWith({ fix_quotes: true });
});

test("custom params input is visible when strip_utms is enabled", () => {
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  expect(
    screen.getByPlaceholderText("ref, tracking_id, campaign"),
  ).toBeInTheDocument();
});

test("custom params input is hidden when strip_utms is disabled", () => {
  const onUpdateConfig = vi.fn();
  const configDisabled = { ...mockConfig, strip_utms: false };

  render(<RulesTab config={configDisabled} onUpdateConfig={onUpdateConfig} />);

  expect(
    screen.queryByPlaceholderText("ref, tracking_id, campaign"),
  ).not.toBeInTheDocument();
});

test("typing shows debouncing indicator", () => {
  vi.useFakeTimers();
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  const input = screen.getByPlaceholderText("ref, tracking_id, campaign");

  fireEvent.change(input, { target: { value: "ref" } });

  expect(screen.getByText("...")).toBeInTheDocument();
});

test("debouncing indicator disappears after debounce completes", async () => {
  vi.useFakeTimers();
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  const input = screen.getByPlaceholderText("ref, tracking_id, campaign");

  fireEvent.change(input, { target: { value: "ref" } });

  expect(screen.getByText("...")).toBeInTheDocument();

  await act(async () => {
    vi.advanceTimersByTime(500);
  });

  expect(screen.queryByText("...")).not.toBeInTheDocument();
  expect(screen.getByText("\u2713")).toBeInTheDocument();
});

test("saved indicator fades away after 1.5 seconds", async () => {
  vi.useFakeTimers();
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  const input = screen.getByPlaceholderText("ref, tracking_id, campaign");

  fireEvent.change(input, { target: { value: "ref" } });

  await act(async () => {
    vi.advanceTimersByTime(500);
  });

  expect(screen.getByText("\u2713")).toBeInTheDocument();

  await act(async () => {
    vi.advanceTimersByTime(1500);
  });

  expect(screen.queryByText("\u2713")).not.toBeInTheDocument();
});

test("rapid keystrokes only trigger one config update", async () => {
  vi.useFakeTimers();
  const onUpdateConfig = vi.fn();

  render(<RulesTab config={mockConfig} onUpdateConfig={onUpdateConfig} />);

  const input = screen.getByPlaceholderText("ref, tracking_id, campaign");

  fireEvent.change(input, { target: { value: "r" } });
  fireEvent.change(input, { target: { value: "re" } });
  fireEvent.change(input, { target: { value: "ref" } });

  await act(async () => {
    vi.advanceTimersByTime(500);
  });

  expect(onUpdateConfig).toHaveBeenCalledTimes(1);
  expect(onUpdateConfig).toHaveBeenCalledWith({
    custom_params: ["ref"],
  });
});
