/// <reference types="@testing-library/jest-dom" />
import React from "react";
import { Checkbox } from "./index";

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

jest.mock("@shared/components/button", () => {
  const MockButton = React.forwardRef<
    HTMLButtonElement,
    React.ButtonHTMLAttributes<HTMLButtonElement>
  >(({ children, ...props }, ref) => (
    <button ref={ref} {...props}>
      {children}
    </button>
  ));
  MockButton.displayName = "MockButton";
  return { Button: MockButton };
});

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

describe("Checkbox", () => {
  describe("rendering", () => {
    it("renders an unchecked checkbox by default", () => {
      render(<Checkbox name="test" />);
      const input = screen.getByRole("checkbox");
      expect(input).not.toBeChecked();
    });

    it("renders a checked checkbox when checked is true", () => {
      render(<Checkbox name="test" checked={true} />);
      const input = screen.getByRole("checkbox");
      expect(input).toBeChecked();
    });

    it("renders with the correct name attribute", () => {
      render(<Checkbox name="agreement" />);
      const input = screen.getByRole("checkbox");
      expect(input).toHaveAttribute("name", "agreement");
    });

    it("renders with the correct value attribute", () => {
      render(<Checkbox name="test" value="yes" />);
      const input = screen.getByRole("checkbox");
      expect(input).toHaveAttribute("value", "yes");
    });

    it("applies displayName correctly", () => {
      expect(Checkbox.displayName).toBe("Checkbox");
    });
  });

  describe("label", () => {
    it("renders a string label", () => {
      render(<Checkbox name="test" label="Accept terms" />);
      expect(screen.getByText("Accept terms")).toBeInTheDocument();
    });

    it("renders a ReactNode label", () => {
      render(
        <Checkbox
          name="test"
          label={<span data-testid="custom-label">Custom</span>}
        />
      );
      expect(screen.getByTestId("custom-label")).toBeInTheDocument();
    });

    it("does not render label element when label is not provided", () => {
      const { container } = render(<Checkbox name="test" />);
      const labels = container.querySelectorAll("label");
      // Only the icon label, no text label
      expect(labels.length).toBe(1);
    });

    it("applies labelClassName to the label", () => {
      render(
        <Checkbox name="test" label="Label" labelClassName="custom-label" />
      );
      const label = screen.getByText("Label");
      expect(label.className).toContain("custom-label");
    });

    it("applies error class to label when error is true", () => {
      render(<Checkbox name="test" label="Label" error={true} />);
      const label = screen.getByText("Label");
      expect(label.className).toContain("text-text-critical");
    });
  });

  describe("interactive behavior", () => {
    it("calls onChange with boolean when handler expects a parameter", () => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const handleChange = jest.fn((_isChecked: boolean) => undefined);
      render(<Checkbox name="test" onChange={handleChange} />);
      const input = screen.getByRole("checkbox");
      fireEvent.click(input);
      expect(handleChange).toHaveBeenCalledWith(true);
    });

    it("calls onChange without parameters for zero-arity handler", () => {
      const handleChange = jest.fn();
      // Override length to simulate zero-arity
      Object.defineProperty(handleChange, "length", { value: 0 });
      render(<Checkbox name="test" onChange={handleChange} />);
      const input = screen.getByRole("checkbox");
      fireEvent.click(input);
      expect(handleChange).toHaveBeenCalled();
    });

    it("does not call onChange when disabled", () => {
      const handleChange = jest.fn();
      render(<Checkbox name="test" onChange={handleChange} disabled={true} />);
      const input = screen.getByRole("checkbox");
      fireEvent.click(input);
      expect(handleChange).not.toHaveBeenCalled();
    });

    it("does not call onChange when state is disabled", () => {
      const handleChange = jest.fn();
      render(<Checkbox name="test" onChange={handleChange} state="disabled" />);
      const input = screen.getByRole("checkbox");
      fireEvent.click(input);
      expect(handleChange).not.toHaveBeenCalled();
    });
  });

  describe("disabled state", () => {
    it("sets disabled attribute when disabled prop is true", () => {
      render(<Checkbox name="test" disabled={true} />);
      const input = screen.getByRole("checkbox");
      expect(input).toBeDisabled();
    });

    it("sets disabled attribute when state is disabled", () => {
      render(<Checkbox name="test" state="disabled" />);
      const input = screen.getByRole("checkbox");
      expect(input).toBeDisabled();
    });

    it("applies disabled styling to unchecked icon", () => {
      const { container } = render(<Checkbox name="test" disabled={true} />);
      const rect = container.querySelector("rect");
      expect(rect).toHaveClass("fill-checkbox-bg-surface-disabled");
    });

    it("applies disabled styling to checked icon", () => {
      const { container } = render(
        <Checkbox name="test" disabled={true} checked={true} />
      );
      const rect = container.querySelector("rect");
      expect(rect).toHaveClass("fill-checkbox-bg-surface-selected-disabled");
    });
  });

  describe("focus state", () => {
    it("applies focus outline class when state is focus", () => {
      const { container } = render(<Checkbox name="test" state="focus" />);
      const label = container.querySelector("label");
      expect(label?.className).toContain("outline");
    });
  });

  describe("required", () => {
    it("sets required attribute when required is true", () => {
      render(<Checkbox name="test" required={true} />);
      const input = screen.getByRole("checkbox");
      expect(input).toBeRequired();
    });
  });

  describe("id handling", () => {
    it("uses provided id for input and label", () => {
      render(<Checkbox name="test" id="custom-id" label="Label" />);
      const input = screen.getByRole("checkbox");
      expect(input).toHaveAttribute("id", "custom-id");
    });

    it("falls back to name when id is not provided", () => {
      render(<Checkbox name="fallback-name" label="Label" />);
      const input = screen.getByRole("checkbox");
      expect(input).toHaveAttribute("id", "fallback-name");
    });
  });

  describe("data-cy attribute", () => {
    it("passes data-cy to the input element", () => {
      render(<Checkbox name="test" data-cy="checkbox-cy" />);
      const input = screen.getByRole("checkbox");
      expect(input).toHaveAttribute("data-cy", "checkbox-cy");
    });
  });

  describe("renderInfoIcon", () => {
    it("renders info icon button when renderInfoIcon is provided", () => {
      const onClick = jest.fn();
      render(
        <Checkbox
          name="test"
          renderInfoIcon={{ onClick, dataTestId: "info-btn" }}
        />
      );
      expect(screen.getByTestId("info-btn")).toBeInTheDocument();
    });

    it("calls onClick when info icon is clicked", () => {
      const onClick = jest.fn();
      render(
        <Checkbox
          name="test"
          renderInfoIcon={{ onClick, dataTestId: "info-btn" }}
        />
      );
      fireEvent.click(screen.getByTestId("info-btn"));
      expect(onClick).toHaveBeenCalledTimes(1);
    });

    it("does not render info icon when renderInfoIcon is not provided", () => {
      const { container } = render(<Checkbox name="test" />);
      const buttons = container.querySelectorAll("button");
      expect(buttons.length).toBe(0);
    });

    it("applies the provided iconSize to the info icon SVG dimensions", () => {
      const onClick = jest.fn();
      render(
        <Checkbox
          name="test"
          renderInfoIcon={{ onClick, dataTestId: "info-btn", iconSize: 20 }}
        />
      );
      const svg = screen.getByTestId("info-btn").querySelector("svg");
      expect(svg?.getAttribute("width")).toBe("20");
      expect(svg?.getAttribute("height")).toBe("20");
    });

    it("defaults the info icon SVG dimensions to 24 when iconSize is not provided", () => {
      const onClick = jest.fn();
      render(
        <Checkbox
          name="test"
          renderInfoIcon={{ onClick, dataTestId: "info-btn" }}
        />
      );
      const svg = screen.getByTestId("info-btn").querySelector("svg");
      expect(svg?.getAttribute("width")).toBe("24");
      expect(svg?.getAttribute("height")).toBe("24");
    });
  });

  describe("containerClassName", () => {
    it("applies containerClassName to the wrapper div", () => {
      const { container } = render(
        <Checkbox name="test" containerClassName="wrapper-class" />
      );
      const wrapper = container.firstChild as HTMLElement;
      expect(wrapper.className).toContain("wrapper-class");
    });
  });

  describe("checked icon rendering", () => {
    it("renders checkmark SVG when checked", () => {
      const { container } = render(<Checkbox name="test" checked={true} />);
      const paths = container.querySelectorAll("path");
      // Checked state has a checkmark path
      expect(paths.length).toBeGreaterThan(0);
    });

    it("renders empty box SVG when unchecked", () => {
      const { container } = render(<Checkbox name="test" checked={false} />);
      const rects = container.querySelectorAll("rect");
      // Unchecked state has border rects
      expect(rects.length).toBeGreaterThan(0);
    });
  });
});
