import React from "react";
import { SearchBlock } from "./index";
import { SearchBlockProps } from "./types";

import { fireEvent, render, screen } from "@testing-library/react";

// Mock dependencies
jest.mock("@shared/components/button", () => ({
  Button: ({ children, onClick, type, className, ...rest }: any) => (
    <button onClick={onClick} type={type} className={className} {...rest}>
      {children}
    </button>
  ),
}));

jest.mock("@shared/components/input", () => ({
  Input: ({
    value,
    onChange,
    placeholder,
    className,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    containerClassName,
    ...rest
  }: any) => (
    <input
      value={value}
      onChange={onChange}
      placeholder={placeholder}
      className={className}
      data-testid="search-input"
      {...rest}
    />
  ),
}));

jest.mock("@shared/components/material-icon", () => ({
  MaterialIcon: ({ name, className }: any) => (
    <span data-testid={`icon-${name}`} className={className}>
      {name}
    </span>
  ),
}));

jest.mock("@shared/components/text", () => ({
  Text: ({ as: Tag = "span", children, className }: any) => (
    <Tag className={className}>{children}</Tag>
  ),
}));

jest.mock("@shared/utils", () => ({
  cx: (...args: any[]) => args.filter(Boolean).join(" "),
}));

const defaultProps: SearchBlockProps = {
  title: "Search Our Plans",
  backgroundColor: "white",
  color: "dark",
};

describe("SearchBlock", () => {
  describe("Rendering", () => {
    it("renders with data-testid", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.getByTestId("search-block")).toBeInTheDocument();
    });

    it("renders title", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.getByText("Search Our Plans")).toBeInTheDocument();
    });

    it("renders with default anchorId", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.getByTestId("search-block")).toHaveAttribute(
        "id",
        "SearchBlock"
      );
    });

    it("renders with custom anchorId", () => {
      render(<SearchBlock {...defaultProps} anchorId="custom-search" />);
      expect(screen.getByTestId("search-block")).toHaveAttribute(
        "id",
        "custom-search"
      );
    });

    it("renders search input with placeholder", () => {
      render(
        <SearchBlock
          {...defaultProps}
          searchInputPlaceholder="Enter your address"
        />
      );
      expect(screen.getByTestId("search-input")).toHaveAttribute(
        "placeholder",
        "Enter your address"
      );
    });

    it("renders search icon button", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.getByTestId("icon-search")).toBeInTheDocument();
    });

    it("renders submit button with type submit", () => {
      render(<SearchBlock {...defaultProps} />);
      const submitBtn = screen.getByTestId("icon-search").closest("button");
      expect(submitBtn).toHaveAttribute("type", "submit");
    });
  });

  describe("Optional content", () => {
    it("renders subtitle when provided", () => {
      render(<SearchBlock {...defaultProps} subTitle="Find the best plan" />);
      expect(screen.getByText("Find the best plan")).toBeInTheDocument();
    });

    it("does not render subtitle when not provided", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.queryByText("Find the best plan")).not.toBeInTheDocument();
    });

    it("renders searchDescription when provided", () => {
      render(
        <SearchBlock
          {...defaultProps}
          searchDescription="Enter your ZIP code"
        />
      );
      expect(screen.getByText("Enter your ZIP code")).toBeInTheDocument();
    });

    it("does not render searchDescription when not provided", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.queryByText("Enter your ZIP code")).not.toBeInTheDocument();
    });

    it("renders caption ReactNode when provided", () => {
      render(
        <SearchBlock
          {...defaultProps}
          caption={<div data-testid="caption">Caption content</div>}
        />
      );
      expect(screen.getByTestId("caption")).toBeInTheDocument();
    });

    it("does not render caption when not provided", () => {
      render(<SearchBlock {...defaultProps} />);
      expect(screen.queryByTestId("caption")).not.toBeInTheDocument();
    });

    it("renders basicCaption ReactNode when provided", () => {
      render(
        <SearchBlock
          {...defaultProps}
          basicCaption={<p data-testid="basic-caption">Basic caption</p>}
        />
      );
      expect(screen.getByTestId("basic-caption")).toBeInTheDocument();
    });
  });

  describe("Heading levels", () => {
    it("renders title as h2 when enableHeading is false/undefined", () => {
      render(<SearchBlock {...defaultProps} />);
      const el = screen.getByText("Search Our Plans");
      expect(el.tagName).toBe("H2");
    });

    it("renders title as h1 when enableHeading is true", () => {
      render(<SearchBlock {...defaultProps} enableHeading={true} />);
      const el = screen.getByText("Search Our Plans");
      expect(el.tagName).toBe("H1");
    });
  });

  describe("Background and color themes", () => {
    it("applies supporting background class", () => {
      render(<SearchBlock {...defaultProps} backgroundColor="supporting" />);
      expect(screen.getByTestId("search-block")).toHaveClass(
        "bg-bg-fill-brand-supporting"
      );
    });

    it("applies white background class", () => {
      render(<SearchBlock {...defaultProps} backgroundColor="white" />);
      expect(screen.getByTestId("search-block")).toHaveClass("bg-bg");
    });

    it("applies brand background class", () => {
      render(<SearchBlock {...defaultProps} backgroundColor="brand" />);
      expect(screen.getByTestId("search-block")).toHaveClass(
        "bg-bg-fill-brand"
      );
    });

    it("applies dark text color", () => {
      render(<SearchBlock {...defaultProps} color="dark" />);
      expect(screen.getByTestId("search-block")).toHaveClass("text-text");
    });

    it("applies light (white) text color", () => {
      render(<SearchBlock {...defaultProps} color="light" />);
      expect(screen.getByTestId("search-block")).toHaveClass("text-white");
    });
  });

  describe("Form submission", () => {
    it("calls onSubmit with searchText on form submit", () => {
      const mockSubmit = jest.fn();
      render(<SearchBlock {...defaultProps} onSubmit={mockSubmit} />);
      const input = screen.getByTestId("search-input");
      fireEvent.change(input, { target: { value: "90210" } });
      const form = input.closest("form")!;
      fireEvent.submit(form);
      expect(mockSubmit).toHaveBeenCalledWith({ searchText: "90210" });
    });

    it("calls onSubmit with empty string when no text entered", () => {
      const mockSubmit = jest.fn();
      render(<SearchBlock {...defaultProps} onSubmit={mockSubmit} />);
      const form = screen.getByTestId("search-input").closest("form")!;
      fireEvent.submit(form);
      expect(mockSubmit).toHaveBeenCalledWith({ searchText: "" });
    });

    it("does not throw when onSubmit is not provided", () => {
      render(<SearchBlock {...defaultProps} />);
      const form = screen.getByTestId("search-input").closest("form")!;
      expect(() => fireEvent.submit(form)).not.toThrow();
    });

    it("prevents default form submission", () => {
      const mockSubmit = jest.fn();
      render(<SearchBlock {...defaultProps} onSubmit={mockSubmit} />);
      const form = screen.getByTestId("search-input").closest("form")!;
      const submitEvent = new Event("submit", {
        bubbles: true,
        cancelable: true,
      });
      const prevented = !form.dispatchEvent(submitEvent);
      expect(prevented).toBe(true);
    });
  });

  describe("Input interaction", () => {
    it("updates input value on change", () => {
      render(<SearchBlock {...defaultProps} />);
      const input = screen.getByTestId("search-input") as HTMLInputElement;
      fireEvent.change(input, { target: { value: "test query" } });
      expect(input.value).toBe("test query");
    });

    it("submits the latest typed value", () => {
      const mockSubmit = jest.fn();
      render(<SearchBlock {...defaultProps} onSubmit={mockSubmit} />);
      const input = screen.getByTestId("search-input");
      fireEvent.change(input, { target: { value: "first" } });
      fireEvent.change(input, { target: { value: "second" } });
      const form = input.closest("form")!;
      fireEvent.submit(form);
      expect(mockSubmit).toHaveBeenCalledWith({ searchText: "second" });
    });
  });
});
