import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
import { FilterForm } from "../FilterForm";
import type { FilterConfig } from "../../../types/config";

// Mock the useFilterConfig hook so tests don't make real API calls.
vi.mock("../../../hooks/useFilterConfig");

import { useFilterConfig } from "../../../hooks/useFilterConfig";

const mockUseFilterConfig = vi.mocked(useFilterConfig);

const mockConfig: FilterConfig = {
  name: "sshd",
  filename: "sshd.conf",
  before: null,
  after: null,
  variables: {},
  prefregex: null,
  failregex: ["^<HOST> port \\d+"],
  ignoreregex: [],
  maxlines: null,
  datepattern: null,
  journalmatch: null,
  active: false,
  used_by_jails: [],
  source_file: "/etc/fail2ban/filter.d/sshd.conf",
  has_local_override: false,
};

function renderForm(name: string) {
  return render(
    <FluentProvider theme={webLightTheme}>
      <FilterForm name={name} />
    </FluentProvider>,
  );
}

describe("FilterForm", () => {
  it("shows skeleton while loading", () => {
    mockUseFilterConfig.mockReturnValue({
      config: null,
      loading: true,
      error: null,
      saving: false,
      saveError: null,
      refresh: vi.fn(),
      save: vi.fn(),
    });

    renderForm("sshd");
    // aria-label on Skeleton container
    expect(screen.getByLabelText(/loading sshd/i)).toBeInTheDocument();
  });

  it("shows error message when loading fails", () => {
    mockUseFilterConfig.mockReturnValue({
      config: null,
      loading: false,
      error: "Network error",
      saving: false,
      saveError: null,
      refresh: vi.fn(),
      save: vi.fn(),
    });

    renderForm("sshd");
    expect(screen.getByText(/network error/i)).toBeInTheDocument();
  });

  it("shows fallback error when config is null with no error message", () => {
    mockUseFilterConfig.mockReturnValue({
      config: null,
      loading: false,
      error: null,
      saving: false,
      saveError: null,
      refresh: vi.fn(),
      save: vi.fn(),
    });

    renderForm("sshd");
    expect(screen.getByText(/failed to load filter config/i)).toBeInTheDocument();
  });

  it("renders form accordion sections when config is loaded", () => {
    mockUseFilterConfig.mockReturnValue({
      config: mockConfig,
      loading: false,
      error: null,
      saving: false,
      saveError: null,
      refresh: vi.fn(),
      save: vi.fn(),
    });

    renderForm("sshd");
    // Accordion headers should be visible
    expect(screen.getByText(/includes/i)).toBeInTheDocument();
    expect(screen.getByText(/definition/i)).toBeInTheDocument();
  });

  it("passes the filter name to useFilterConfig", () => {
    mockUseFilterConfig.mockReturnValue({
      config: null,
      loading: true,
      error: null,
      saving: false,
      saveError: null,
      refresh: vi.fn(),
      save: vi.fn(),
    });

    renderForm("nginx");
    expect(mockUseFilterConfig).toHaveBeenCalledWith("nginx");
  });
});
