import React from "react";
import { Button } from "./index";

import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import "@testing-library/jest-dom/jest-globals";
import { fireEvent, render, screen } from "@testing-library/react";

jest.mock("@shared/components/brand-button", () => ({
  BrandButton: ({
    as,
    href,
    text,
    label,
    iconName,
    iconSize,
    iconFill,
    onClick,
    id,
    variant,
    fullWidth,
    size,
    buttonClassName,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    ...rest
  }: any) => {
    const Tag = as || "button";
    return (
      <Tag
        data-testid="brand-button"
        href={href}
        id={id}
        data-variant={variant}
        data-full-width={fullWidth}
        data-size={size}
        data-icon-name={iconName}
        data-icon-size={iconSize}
        data-icon-fill={iconFill}
        className={buttonClassName}
        onClick={onClick}
      >
        {label} {text}
      </Tag>
    );
  },
}));

jest.mock("@shared/components/button", () => ({
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  Button: ({ onClick, className, children, ...rest }: any) => (
    <button data-testid="core-button" className={className} onClick={onClick}>
      {children}
    </button>
  ),
}));

jest.mock("@shared/components/link", () => ({
  Link: ({
    children,
    href,
    target,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    variant,
    className,
    title,
    onClick,
  }: any) => (
    <a
      data-testid="link"
      href={href}
      target={target}
      className={className}
      title={title}
      onClick={onClick}
    >
      {children}
    </a>
  ),
}));

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

jest.mock("@shared/utils/utm", () => ({
  buildPreservedQueryHref: (href: string, search: string) => `${href}${search}`,
}));

describe("Button", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe("showButtonAs='solid' (default)", () => {
    it("renders BrandButton as anchor when href is provided", () => {
      render(<Button buttonLabel="Click" href="/page" />);
      const btn = screen.getByTestId("brand-button");
      expect(btn.tagName).toBe("A");
      expect(btn).toHaveAttribute("href", "/page");
      expect(btn).toHaveTextContent("Click");
    });

    it("renders BrandButton as button when href is not provided", () => {
      render(<Button buttonLabel="Click" />);
      const btn = screen.getByTestId("brand-button");
      expect(btn.tagName).toBe("BUTTON");
    });

    it("passes variant, anchorId, fullWidth, size, buttonClassName", () => {
      render(
        <Button
          buttonLabel="X"
          buttonVariant="secondary"
          anchorId="test-id"
          fullWidth={true}
          size="lg"
          buttonClassName="custom"
        />
      );
      const btn = screen.getByTestId("brand-button");
      expect(btn).toHaveAttribute("data-variant", "secondary");
      expect(btn).toHaveAttribute("id", "test-id");
      expect(btn).toHaveAttribute("data-full-width", "true");
      expect(btn).toHaveAttribute("data-size", "lg");
      expect(btn).toHaveClass("custom");
    });

    it("passes buttonPrefix as label", () => {
      render(<Button buttonLabel="Main" buttonPrefix="Prefix" />);
      expect(screen.getByTestId("brand-button")).toHaveTextContent(
        "Prefix Main"
      );
    });
  });

  describe("showButtonAs='text'", () => {
    it("renders Link with buttonLabel and target", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="Learn more"
          href="/info"
          target="_self"
        />
      );
      const link = screen.getByTestId("link");
      expect(link).toHaveAttribute("href", "/info");
      expect(link).toHaveAttribute("target", "_self");
      expect(link).toHaveAttribute("title", "Learn more");
    });

    it("applies linkClassName and linkVariant", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="Go"
          linkClassName="extra"
          linkVariant="unstyled"
        />
      );
      const link = screen.getByTestId("link");
      expect(link.className).toContain("extra");
    });

    it("renders MaterialIcon when buttonIconName is provided", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="Go"
          buttonIconName="arrow_forward"
          iconSize={20}
          iconFill={1}
        />
      );
      const icon = screen.getByTestId("material-icon");
      expect(icon).toHaveAttribute("data-name", "arrow_forward");
      expect(icon).toHaveAttribute("data-size", "20");
      expect(icon).toHaveAttribute("data-fill", "1");
    });

    it("does not render MaterialIcon when buttonIconName is absent", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="Go"
          iconName="arrow_forward"
          iconSize={20}
          iconFill={1}
        />
      );
      expect(screen.queryByTestId("material-icon")).not.toBeInTheDocument();
    });

    it("does not render MaterialIcon when iconName is not provided", () => {
      render(<Button showButtonAs="text" buttonLabel="Go" />);
      expect(screen.queryByTestId("material-icon")).not.toBeInTheDocument();
    });

    it("renders buttonIconName icon before label when buttonIconPosition is left", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="See Jobs"
          href="/jobs"
          buttonIconName="expand_circle_right"
          buttonIconPosition="left"
        />
      );
      const link = screen.getByTestId("link");
      const icon = screen.getByTestId("material-icon");
      expect(icon).toBeInTheDocument();
      expect(link.firstElementChild).toBe(icon);
    });

    it("renders buttonIconName icon after label by default", () => {
      render(
        <Button
          showButtonAs="text"
          buttonLabel="See Jobs"
          href="/jobs"
          buttonIconName="expand_circle_right"
        />
      );
      const link = screen.getByTestId("link");
      const icon = screen.getByTestId("material-icon");
      expect(icon).toBeInTheDocument();
      expect(link.lastElementChild).toBe(icon);
      expect(link.className).toContain("no-underline");
      expect(link.className).toContain("inline-flex");
    });
  });

  describe("buttonIconName behavior", () => {
    it("renders solid CTA icon before label when buttonIconPosition is left", () => {
      render(
        <Button
          buttonLabel="See Jobs"
          href="/jobs"
          buttonIconName="expand_circle_right"
          buttonIconPosition="left"
          iconSize={20}
          iconFill={1}
        />
      );
      const link = screen.getByRole("link", { name: /see jobs/i });
      expect(link).toHaveAttribute("data-icon-name", "expand_circle_right");
      expect(link).toHaveAttribute("data-icon-size", "20");
      expect(link).toHaveAttribute("data-icon-fill", "1");
      expect(link).toHaveClass("flex-row-reverse");
    });

    it("renders solid CTA icon after label when buttonIconPosition is right", () => {
      render(
        <Button
          buttonLabel="See Jobs"
          href="/jobs"
          buttonIconName="expand_circle_right"
          buttonIconPosition="right"
        />
      );
      const link = screen.getByRole("link", { name: /see jobs/i });
      expect(link).toHaveAttribute("data-icon-name", "expand_circle_right");
      expect(link).not.toHaveClass("flex-row-reverse");
    });

    it("passes through non-standard variant values", () => {
      render(
        <Button
          buttonLabel="See Jobs"
          href="/jobs"
          buttonVariant={"primary_navy" as any}
        />
      );
      const button = screen.getByTestId("brand-button");
      expect(button).toHaveAttribute("data-variant", "primary_navy");
    });

  });

  describe("showButtonAs='unstyled'", () => {
    it("renders CoreButton", () => {
      render(<Button showButtonAs="unstyled" buttonLabel="Plain" />);
      expect(screen.getByTestId("core-button")).toBeInTheDocument();
    });
  });

  describe("showButtonAs default case", () => {
    it("renders CoreButton for unknown showButtonAs value", () => {
      render(<Button showButtonAs={"other" as any} buttonLabel="Fallback" />);
      expect(screen.getByTestId("core-button")).toBeInTheDocument();
    });
  });

  describe("preDefinedFunctionExecution", () => {
    it("renders checkPlans when preDefinedFunctionExecution is 'check availability'", () => {
      const renderCheckPlans = jest.fn(() => (
        <div data-testid="check-plans">Plans</div>
      ));
      render(
        <Button
          preDefinedFunctionExecution="check availability"
          renderCheckPlans={renderCheckPlans}
          buttonLabel="Check"
        />
      );
      expect(screen.getByTestId("check-plans")).toBeInTheDocument();
      expect(renderCheckPlans).toHaveBeenCalledWith(
        expect.objectContaining({ ctaText: "Check" })
      );
    });

    it("falls back to normal CTA when renderCheckPlans is not provided", () => {
      render(<Button preDefinedFunctionExecution="check availability" />);
      expect(screen.getByTestId("brand-button")).toBeInTheDocument();
    });
  });

  describe("onClick and modal handling", () => {
    it("calls onClick on solid button click (no href)", () => {
      const onClick = jest.fn();
      render(<Button buttonLabel="Click" onClick={onClick} />);
      fireEvent.click(screen.getByTestId("brand-button"));
      expect(onClick).toHaveBeenCalled();
    });

    it("calls onClick on solid link click (with href)", () => {
      const onClick = jest.fn();
      render(<Button buttonLabel="Click" href="/page" onClick={onClick} />);
      fireEvent.click(screen.getByTestId("brand-button"));
      expect(onClick).toHaveBeenCalled();
    });

    it("calls onClick on text link click", () => {
      const onClick = jest.fn();
      render(<Button showButtonAs="text" buttonLabel="Go" onClick={onClick} />);
      fireEvent.click(screen.getByTestId("link"));
      expect(onClick).toHaveBeenCalled();
    });

    it("calls onModalButtonClick when clickToOpen is 'modal'", () => {
      const onModalButtonClick = jest.fn();
      render(
        <Button
          buttonLabel="Open"
          clickToOpen="modal"
          tabmodalNameToOpen="my-modal"
          onModalButtonClick={onModalButtonClick}
        />
      );
      fireEvent.click(screen.getByTestId("brand-button"));
      expect(onModalButtonClick).toHaveBeenCalledWith("my-modal");
    });

    it("does not call onModalButtonClick when clickToOpen is not 'modal'", () => {
      const onModalButtonClick = jest.fn();
      render(
        <Button
          buttonLabel="Open"
          clickToOpen="other"
          onModalButtonClick={onModalButtonClick}
        />
      );
      fireEvent.click(screen.getByTestId("brand-button"));
      expect(onModalButtonClick).not.toHaveBeenCalled();
    });

    it("calls onModalButtonClick on text link click when clickToOpen is 'modal'", () => {
      const onModalButtonClick = jest.fn();
      render(
        <Button
          showButtonAs="text"
          buttonLabel="Open"
          clickToOpen="modal"
          tabmodalNameToOpen="tab1"
          onModalButtonClick={onModalButtonClick}
        />
      );
      fireEvent.click(screen.getByTestId("link"));
      expect(onModalButtonClick).toHaveBeenCalledWith("tab1");
    });

    it("prevents anchor navigation and opens modal when href is present and clickToOpen is 'modal'", () => {
      const onModalButtonClick = jest.fn();
      render(
        <Button
          buttonLabel="Open"
          href="https://example.com"
          clickToOpen="modal"
          tabmodalNameToOpen="my-modal"
          onModalButtonClick={onModalButtonClick}
        />
      );
      // fireEvent.click returns false when a handler called preventDefault().
      const notCancelled = fireEvent.click(screen.getByTestId("brand-button"));
      expect(notCancelled).toBe(false);
      expect(onModalButtonClick).toHaveBeenCalledWith("my-modal");
    });

    it("prevents anchor navigation when href is present and clickToOpen is 'clickId'", () => {
      const scrollIntoView = jest.fn();
      const targetEl = document.createElement("div");
      targetEl.scrollIntoView = scrollIntoView;
      const getElementByIdSpy = jest
        .spyOn(document, "getElementById")
        .mockReturnValue(targetEl);
      render(
        <Button
          buttonLabel="Scroll"
          href="https://example.com"
          clickToOpen="clickId"
          idNameToOpen="section-1"
        />
      );
      const notCancelled = fireEvent.click(screen.getByTestId("brand-button"));
      expect(notCancelled).toBe(false);
      expect(scrollIntoView).toHaveBeenCalled();
      getElementByIdSpy.mockRestore();
    });

    it("does not prevent anchor navigation for a normal href link", () => {
      const onModalButtonClick = jest.fn();
      render(
        <Button
          buttonLabel="Go"
          href="https://example.com"
          onModalButtonClick={onModalButtonClick}
        />
      );
      const notCancelled = fireEvent.click(screen.getByTestId("brand-button"));
      expect(notCancelled).toBe(true);
      expect(onModalButtonClick).not.toHaveBeenCalled();
    });
  });

  describe("preserveQueryParameters", () => {
    it("uses buildPreservedQueryHref when preserveQueryParameters is true and search exists", () => {
      Object.defineProperty(window, "location", {
        value: { search: "?foo=bar" },
        writable: true,
      });
      render(
        <Button
          buttonLabel="Go"
          href="/page"
          preserveQueryParameters={true}
          showButtonAs="solid"
        />
      );
      expect(screen.getByTestId("brand-button")).toHaveAttribute(
        "href",
        "/page?foo=bar"
      );
    });

    it("uses original href when preserveQueryParameters is false", () => {
      Object.defineProperty(window, "location", {
        value: { search: "?foo=bar" },
        writable: true,
      });
      render(<Button buttonLabel="Go" href="/page" showButtonAs="solid" />);
      expect(screen.getByTestId("brand-button")).toHaveAttribute(
        "href",
        "/page"
      );
    });

    it("uses original href when search is empty", () => {
      Object.defineProperty(window, "location", {
        value: { search: "" },
        writable: true,
      });
      render(
        <Button
          buttonLabel="Go"
          href="/page"
          preserveQueryParameters={true}
          showButtonAs="solid"
        />
      );
      expect(screen.getByTestId("brand-button")).toHaveAttribute(
        "href",
        "/page"
      );
    });
  });
});
