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

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

// Mock dependencies
/* eslint-disable react/prop-types */
jest.mock("@shared/components/link", () => ({
  Link: ({
    children,
    className,
    href,
    ...props
  }: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
    children: React.ReactNode;
  }) => (
    <a href={href} className={className} {...props}>
      {children}
    </a>
  ),
}));
/* eslint-enable react/prop-types */

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

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

describe("CallButton", () => {
  describe("rendering", () => {
    it("renders children text content", () => {
      render(<CallButton href="tel:+1234567890">Call Us</CallButton>);
      expect(screen.getByText("Call Us")).toBeInTheDocument();
    });

    it("renders the call icon", () => {
      render(<CallButton href="tel:+1234567890">Call</CallButton>);
      expect(screen.getByTestId("material-icon-call")).toBeInTheDocument();
    });

    it("renders an anchor element via Link", () => {
      render(<CallButton href="tel:+1234567890">Call</CallButton>);
      const link = screen.getByRole("link");
      expect(link).toHaveAttribute("href", "tel:+1234567890");
    });

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

  describe("size variants", () => {
    it("applies sm size classes", () => {
      render(
        <CallButton href="tel:123" size="sm">
          Call
        </CallButton>
      );
      const link = screen.getByRole("link");
      expect(link.className).toContain("h-6");
      expect(link.className).toContain("text-xs");
    });

    it("applies md size classes by default", () => {
      render(<CallButton href="tel:123">Call</CallButton>);
      const link = screen.getByRole("link");
      expect(link.className).toContain("h-8");
      expect(link.className).toContain("text-sm");
    });

    it("applies lg size classes", () => {
      render(
        <CallButton href="tel:123" size="lg">
          Call
        </CallButton>
      );
      const link = screen.getByRole("link");
      expect(link.className).toContain("h-10");
      expect(link.className).toContain("text-base");
    });
  });

  describe("buttonStyle variants", () => {
    it("applies primary style classes by default", () => {
      render(<CallButton href="tel:123">Call</CallButton>);
      const link = screen.getByRole("link");
      expect(link.className).toContain("border-border");
      expect(link.className).toContain("text-text");
    });

    it("applies primary style classes when explicitly set", () => {
      render(
        <CallButton href="tel:123" buttonStyle="primary">
          Call
        </CallButton>
      );
      const link = screen.getByRole("link");
      expect(link.className).toContain("border-border");
    });
  });

  describe("blinking dot", () => {
    it("does not render blinking dot by default", () => {
      const { container } = render(
        <CallButton href="tel:123">Call</CallButton>
      );
      const dot = container.querySelector(".animate-blink");
      expect(dot).not.toBeInTheDocument();
    });

    it("renders blinking dot when showBlinkDot is true", () => {
      const { container } = render(
        <CallButton href="tel:123" showBlinkDot={true}>
          Call
        </CallButton>
      );
      const dot = container.querySelector(".animate-blink");
      expect(dot).toBeInTheDocument();
    });

    it("applies correct dot size for sm", () => {
      const { container } = render(
        <CallButton href="tel:123" showBlinkDot={true} size="sm">
          Call
        </CallButton>
      );
      const dot = container.querySelector(".animate-blink");
      expect(dot).toHaveClass("h-2", "w-2");
    });

    it("applies correct dot size for md", () => {
      const { container } = render(
        <CallButton href="tel:123" showBlinkDot={true} size="md">
          Call
        </CallButton>
      );
      const dot = container.querySelector(".animate-blink");
      expect(dot).toHaveClass("h-3", "w-3");
    });

    it("applies correct dot size for lg", () => {
      const { container } = render(
        <CallButton href="tel:123" showBlinkDot={true} size="lg">
          Call
        </CallButton>
      );
      const dot = container.querySelector(".animate-blink");
      expect(dot).toHaveClass("h-4", "w-4");
    });
  });

  describe("prefix", () => {
    it("renders without prefix wrapper when prefix is null", () => {
      const { container } = render(
        <CallButton href="tel:123" prefix={null}>
          Call
        </CallButton>
      );
      // Should not have the outer wrapper span
      const wrapper = container.querySelector("span.flex.items-center.gap-2");
      expect(wrapper).not.toBeInTheDocument();
    });

    it("renders without prefix wrapper when prefix is false", () => {
      const { container } = render(
        <CallButton href="tel:123" prefix={false}>
          Call
        </CallButton>
      );
      const wrapper = container.querySelector("span.flex.items-center.gap-2");
      expect(wrapper).not.toBeInTheDocument();
    });

    it("renders without prefix wrapper when prefix is empty string", () => {
      const { container } = render(
        <CallButton href="tel:123" prefix="">
          Call
        </CallButton>
      );
      const wrapper = container.querySelector("span.flex.items-center.gap-2");
      expect(wrapper).not.toBeInTheDocument();
    });

    it("renders string prefix in a span", () => {
      render(
        <CallButton href="tel:123" prefix="Call now:">
          555-1234
        </CallButton>
      );
      expect(screen.getByText("Call now:")).toBeInTheDocument();
    });

    it("renders numeric prefix in a span", () => {
      render(
        <CallButton href="tel:123" prefix={42}>
          Call
        </CallButton>
      );
      expect(screen.getByText("42")).toBeInTheDocument();
    });

    it("renders ReactNode prefix directly", () => {
      render(
        <CallButton
          href="tel:123"
          prefix={<strong data-testid="custom-prefix">Custom</strong>}
        >
          Call
        </CallButton>
      );
      expect(screen.getByTestId("custom-prefix")).toBeInTheDocument();
    });

    it("applies containerClassName to the outer wrapper", () => {
      const { container } = render(
        <CallButton
          href="tel:123"
          prefix="Prefix"
          containerClassName="my-container"
        >
          Call
        </CallButton>
      );
      const wrapper = container.firstChild as HTMLElement;
      expect(wrapper.className).toContain("my-container");
    });
  });

  describe("custom className", () => {
    it("applies custom className to the link", () => {
      render(
        <CallButton href="tel:123" className="custom-class">
          Call
        </CallButton>
      );
      const link = screen.getByRole("link");
      expect(link.className).toContain("custom-class");
    });
  });

  describe("accessibility", () => {
    it("passes aria attributes to the link", () => {
      render(
        <CallButton href="tel:123" aria-label="Call support">
          Call
        </CallButton>
      );
      const link = screen.getByRole("link");
      expect(link).toHaveAttribute("aria-label", "Call support");
    });
  });
});
