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

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

import "@testing-library/jest-dom";

describe("BrandButton", () => {
  describe("Rendering", () => {
    it("renders as a button by default", () => {
      render(<BrandButton text="Click me" />);
      expect(screen.getByRole("button")).toBeInTheDocument();
      expect(screen.getByRole("button")).toHaveTextContent("Click me");
    });

    it("renders as an anchor when as='a'", () => {
      render(<BrandButton as="a" href="/test" text="Link" />);
      const link = screen.getByRole("link");
      expect(link).toBeInTheDocument();
      expect(link).toHaveAttribute("href", "/test");
      expect(link).toHaveTextContent("Link");
    });

    it("has correct displayName", () => {
      expect(BrandButton.displayName).toBe("BrandButton");
    });

    it("renders text prop content", () => {
      render(<BrandButton text="Submit" />);
      expect(screen.getByText("Submit")).toBeInTheDocument();
    });
  });

  describe("Variants", () => {
    it("applies primary_brand variant classes by default", () => {
      render(<BrandButton text="Primary" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("button--primary_brand");
    });

    it("applies primary_inverse variant classes", () => {
      render(<BrandButton variant="primary_inverse" text="Inverse" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("button--primary_inverse");
    });

    it("applies secondary variant classes", () => {
      render(<BrandButton variant="secondary" text="Secondary" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("button--secondary");
    });
  });

  describe("Loading state", () => {
    it("shows spinner icon when isLoading is true", () => {
      render(<BrandButton isLoading={true} text="Loading" />);
      expect(screen.getByText("progress_activity")).toBeInTheDocument();
    });

    it("disables button when isLoading is true", () => {
      render(<BrandButton isLoading={true} text="Loading" />);
      expect(screen.getByRole("button")).toBeDisabled();
    });

    it("adds loading class when isLoading", () => {
      render(<BrandButton isLoading={true} text="Loading" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("button--loading");
    });

    it("does not show spinner when isLoading is false", () => {
      render(<BrandButton text="Not Loading" />);
      expect(screen.queryByText("progress_activity")).not.toBeInTheDocument();
    });
  });

  describe("Disabled state", () => {
    it("disables button when disabled prop is true", () => {
      render(<BrandButton disabled={true} text="Disabled" />);
      expect(screen.getByRole("button")).toBeDisabled();
    });

    it("adds disabled class when disabled", () => {
      render(<BrandButton disabled={true} text="Disabled" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("button--disabled");
    });

    it("applies cursor-not-allowed when disabled", () => {
      render(<BrandButton disabled={true} text="Disabled" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("cursor-not-allowed");
    });
  });

  describe("Label prop", () => {
    it("renders label and text when label is provided", () => {
      render(<BrandButton label="Starting at" text="$49/mo" />);
      expect(screen.getByText("Starting at")).toBeInTheDocument();
      expect(screen.getByText("$49/mo")).toBeInTheDocument();
    });

    it("wraps label in a span with size class", () => {
      const { container } = render(<BrandButton label="Label" text="Text" />);
      const labelSpan = container.querySelector("span span");
      expect(labelSpan).toHaveTextContent("Label");
    });
  });

  describe("Size prop", () => {
    it("applies base size class", () => {
      render(<BrandButton size={{ base: "small" }} text="Small" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("btn-small");
    });

    it("applies medium size by default", () => {
      render(<BrandButton text="Default" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("btn-medium");
    });

    it("applies responsive md size class for small", () => {
      render(<BrandButton size={{ base: "small", md: "small" }} text="Resp" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("md:btn-small");
    });

    it("applies responsive md size class for medium", () => {
      render(
        <BrandButton size={{ base: "small", md: "medium" }} text="Resp" />
      );
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("md:btn-medium");
    });

    it("applies responsive md size class for large", () => {
      render(<BrandButton size={{ base: "small", md: "large" }} text="Resp" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("md:btn-large");
    });

    it("applies responsive md size class for x-large", () => {
      render(
        <BrandButton size={{ base: "small", md: "x-large" }} text="Resp" />
      );
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("md:btn-x-large");
    });

    it("applies responsive lg size class", () => {
      render(
        <BrandButton size={{ base: "small", lg: "x-large" }} text="Resp" />
      );
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("lg:btn-x-large");
    });

    it("applies x-large label size with label3 class", () => {
      const { container } = render(
        <BrandButton size={{ base: "x-large" }} text="$49" label="Starting" />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("label3");
    });

    it("applies non-x-large label size with label4 class", () => {
      const { container } = render(
        <BrandButton size={{ base: "small" }} text="$49" label="Starting" />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("label4");
    });

    it("applies md label3 for x-large md size", () => {
      const { container } = render(
        <BrandButton
          size={{ base: "small", md: "x-large" }}
          text="$49"
          label="Starting"
        />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("md:label3");
    });

    it("applies md label4 for non-x-large md size", () => {
      const { container } = render(
        <BrandButton
          size={{ base: "small", md: "medium" }}
          text="$49"
          label="Starting"
        />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("md:label4");
    });

    it("applies lg label3 for x-large lg size", () => {
      const { container } = render(
        <BrandButton
          size={{ base: "small", lg: "x-large" }}
          text="$49"
          label="Starting"
        />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("lg:label3");
    });

    it("applies lg label4 for non-x-large lg size", () => {
      const { container } = render(
        <BrandButton
          size={{ base: "small", lg: "large" }}
          text="$49"
          label="Starting"
        />
      );
      const labelSpan = container.querySelector("span span");
      expect(labelSpan?.className).toContain("lg:label4");
    });
  });

  describe("fullWidth", () => {
    it("applies w-full when fullWidth is true", () => {
      render(<BrandButton fullWidth={true} text="Full" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("w-full");
    });

    it("applies w-auto when fullWidth is false", () => {
      render(<BrandButton text="Auto" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("w-auto");
    });
  });

  describe("buttonClassName", () => {
    it("applies custom buttonClassName", () => {
      render(<BrandButton buttonClassName="my-custom-class" text="Custom" />);
      const btn = screen.getByRole("button");
      expect(btn.className).toContain("my-custom-class");
    });
  });

  describe("Ref forwarding", () => {
    it("forwards ref to button element", () => {
      const ref = React.createRef<HTMLButtonElement>();
      render(<BrandButton ref={ref} text="Ref" />);
      expect(ref.current).toBeInstanceOf(HTMLButtonElement);
    });

    it("forwards ref to anchor element", () => {
      const ref = React.createRef<HTMLAnchorElement>();
      render(<BrandButton ref={ref} as="a" href="/test" text="Ref" />);
      expect(ref.current).toBeInstanceOf(HTMLAnchorElement);
    });
  });

  describe("Event handling", () => {
    it("calls onClick handler when clicked", () => {
      const onClick = jest.fn();
      render(<BrandButton text="Click" onClick={onClick} />);
      fireEvent.click(screen.getByRole("button"));
      expect(onClick).toHaveBeenCalledTimes(1);
    });

    it("does not call onClick when disabled", () => {
      const onClick = jest.fn();
      render(<BrandButton text="Click" onClick={onClick} disabled={true} />);
      fireEvent.click(screen.getByRole("button"));
      expect(onClick).not.toHaveBeenCalled();
    });
  });

  describe("Anchor props", () => {
    it("passes anchor-specific props when as='a'", () => {
      render(
        <BrandButton
          as="a"
          href="/test"
          target="_blank"
          rel="noopener"
          text="Link"
        />
      );
      const link = screen.getByRole("link");
      expect(link).toHaveAttribute("target", "_blank");
      expect(link).toHaveAttribute("rel", "noopener");
    });
  });
});
