/**
 * Tests for the DashboardFilterBar component.
 *
 * Covers rendering, active-state reflection, and callback invocation.
 */

import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
import { DashboardFilterBar } from "../DashboardFilterBar";
import type { BanOriginFilter, TimeRange } from "../../types/ban";

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

interface RenderProps {
  timeRange?: TimeRange;
  onTimeRangeChange?: (value: TimeRange) => void;
  originFilter?: BanOriginFilter;
  onOriginFilterChange?: (value: BanOriginFilter) => void;
}

function renderBar({
  timeRange = "24h",
  onTimeRangeChange = vi.fn<(value: TimeRange) => void>(),
  originFilter = "all",
  onOriginFilterChange = vi.fn<(value: BanOriginFilter) => void>(),
}: RenderProps = {}): {
  onTimeRangeChange: (value: TimeRange) => void;
  onOriginFilterChange: (value: BanOriginFilter) => void;
} {
  render(
    <FluentProvider theme={webLightTheme}>
      <DashboardFilterBar
        timeRange={timeRange}
        onTimeRangeChange={onTimeRangeChange}
        originFilter={originFilter}
        onOriginFilterChange={onOriginFilterChange}
      />
    </FluentProvider>,
  );
  return { onTimeRangeChange, onOriginFilterChange };
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

describe("DashboardFilterBar", () => {
  // -------------------------------------------------------------------------
  // 1. Renders all time-range buttons
  // -------------------------------------------------------------------------
  it("renders all four time-range buttons", () => {
    renderBar();
    expect(screen.getByRole("button", { name: /last 24 h/i })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /last 7 days/i })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /last 30 days/i })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /last 365 days/i })).toBeInTheDocument();
  });

  // -------------------------------------------------------------------------
  // 2. Renders all origin-filter buttons
  // -------------------------------------------------------------------------
  it("renders all three origin-filter buttons", () => {
    renderBar();
    expect(screen.getByRole("button", { name: /^all$/i })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /blocklist/i })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: /selfblock/i })).toBeInTheDocument();
  });

  // -------------------------------------------------------------------------
  // 3. Active state matches props
  // -------------------------------------------------------------------------
  it("marks the correct time-range button as active", () => {
    renderBar({ timeRange: "7d" });
    expect(
      screen.getByRole("button", { name: /last 7 days/i }),
    ).toHaveAttribute("aria-pressed", "true");
    expect(
      screen.getByRole("button", { name: /last 24 h/i }),
    ).toHaveAttribute("aria-pressed", "false");
  });

  it("marks the correct origin-filter button as active", () => {
    renderBar({ originFilter: "blocklist" });
    expect(
      screen.getByRole("button", { name: /blocklist/i }),
    ).toHaveAttribute("aria-pressed", "true");
    expect(
      screen.getByRole("button", { name: /^all$/i }),
    ).toHaveAttribute("aria-pressed", "false");
  });

  // -------------------------------------------------------------------------
  // 4. Time-range click fires callback
  // -------------------------------------------------------------------------
  it("calls onTimeRangeChange with the correct value when a time-range button is clicked", async () => {
    const user = userEvent.setup();
    const { onTimeRangeChange } = renderBar({ timeRange: "24h" });
    await user.click(screen.getByRole("button", { name: /last 30 days/i }));
    expect(onTimeRangeChange).toHaveBeenCalledOnce();
    expect(onTimeRangeChange).toHaveBeenCalledWith("30d");
  });

  // -------------------------------------------------------------------------
  // 5. Origin-filter click fires callback
  // -------------------------------------------------------------------------
  it("calls onOriginFilterChange with the correct value when an origin button is clicked", async () => {
    const user = userEvent.setup();
    const { onOriginFilterChange } = renderBar({ originFilter: "all" });
    await user.click(screen.getByRole("button", { name: /selfblock/i }));
    expect(onOriginFilterChange).toHaveBeenCalledOnce();
    expect(onOriginFilterChange).toHaveBeenCalledWith("selfblock");
  });

  // -------------------------------------------------------------------------
  // 6. Already-active button click still fires callback
  // -------------------------------------------------------------------------
  it("calls onTimeRangeChange even when the active button is clicked again", async () => {
    const user = userEvent.setup();
    const { onTimeRangeChange } = renderBar({ timeRange: "24h" });
    await user.click(screen.getByRole("button", { name: /last 24 h/i }));
    expect(onTimeRangeChange).toHaveBeenCalledOnce();
    expect(onTimeRangeChange).toHaveBeenCalledWith("24h");
  });

  it("renders jail and ip input controls when provided", async () => {
    const onJailChange = vi.fn();
    const onIpChange = vi.fn();

    render(
      <FluentProvider theme={webLightTheme}>
        <DashboardFilterBar
          timeRange="24h"
          onTimeRangeChange={vi.fn()}
          originFilter="all"
          onOriginFilterChange={vi.fn()}
          jail=""
          onJailChange={onJailChange}
          ip=""
          onIpChange={onIpChange}
        />
      </FluentProvider>,
    );

    expect(screen.getByText(/Jail/i)).toBeInTheDocument();
    expect(screen.getByText(/IP Address/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/e.g. sshd/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/e.g. 192.168/i)).toBeInTheDocument();

    const jailInput = screen.getByPlaceholderText(/e.g. sshd/i);
    const ipInput = screen.getByPlaceholderText(/e.g. 192.168/i);
    const user = userEvent.setup();

    await user.clear(jailInput);
    await user.type(jailInput, "x");
    expect(onJailChange).toHaveBeenLastCalledWith("x");

    await user.clear(ipInput);
    await user.type(ipInput, "1");
    expect(onIpChange).toHaveBeenLastCalledWith("1");
  });

  it("does not render jail or ip inputs when handlers are missing", () => {
    renderBar();
    expect(screen.queryByText(/Jail/i)).toBeNull();
    expect(screen.queryByText(/IP Address/i)).toBeNull();
  });
});
