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

import React, { createRef, forwardRef } from "react";
import { Image } from "./index";
import { ImageComponentProps } from "./types";

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

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

describe("Image", () => {
  it("has displayName set to Image", () => {
    expect(Image.displayName).toBe("Image");
  });

  describe("native img rendering", () => {
    it("renders a native img element by default", () => {
      render(<Image src="/test.png" alt="Test image" />);
      const img = screen.getByAltText("Test image");
      expect(img.tagName).toBe("IMG");
    });

    it("passes src prop to img", () => {
      render(<Image src="/photo.jpg" alt="Photo" />);
      const img = screen.getByAltText("Photo");
      expect(img).toHaveAttribute("src", "/photo.jpg");
    });

    it("passes alt prop to img", () => {
      render(<Image src="/img.png" alt="My image" />);
      const img = screen.getByAltText("My image");
      expect(img).toBeInTheDocument();
    });

    it("passes className to img", () => {
      render(<Image src="/img.png" alt="Img" className="h-auto w-full" />);
      const img = screen.getByAltText("Img");
      expect(img).toHaveClass("w-full");
      expect(img).toHaveClass("h-auto");
    });

    it("uses empty string className by default", () => {
      render(<Image src="/img.png" alt="Img" />);
      const img = screen.getByAltText("Img");
      expect(img).toBeInTheDocument();
    });

    it("passes additional HTML img attributes", () => {
      render(
        <Image
          src="/img.png"
          alt="Img"
          width={200}
          height={100}
          loading="lazy"
        />
      );
      const img = screen.getByAltText("Img");
      expect(img).toHaveAttribute("width", "200");
      expect(img).toHaveAttribute("height", "100");
      expect(img).toHaveAttribute("loading", "lazy");
    });
  });

  describe("ref forwarding", () => {
    it("forwards ref to native img element", () => {
      const ref = createRef<HTMLImageElement>();
      render(<Image ref={ref} src="/img.png" alt="Ref test" />);
      expect(ref.current).toBeInstanceOf(HTMLImageElement);
      expect(ref.current?.tagName).toBe("IMG");
    });

    it("forwards ref to custom component", () => {
      const ref = createRef<HTMLImageElement>();
      const CustomImage = forwardRef<HTMLImageElement, ImageComponentProps>(
        function CustomImage(props, fwdRef) {
          return <img ref={fwdRef} data-testid="custom-img" {...props} />;
        }
      );
      render(
        <Image ref={ref} as={CustomImage} src="/img.png" alt="Custom ref" />
      );
      expect(ref.current).toBeInstanceOf(HTMLImageElement);
    });
  });

  describe("polymorphic rendering with 'as' prop", () => {
    it("renders custom component when 'as' is provided", () => {
      const CustomImage = (props: any) => (
        <div data-testid="custom-image" data-src={props.src}>
          {props.alt}
        </div>
      );
      render(<Image as={CustomImage} src="/custom.png" alt="Custom" />);
      expect(screen.getByTestId("custom-image")).toBeInTheDocument();
      expect(screen.getByTestId("custom-image")).toHaveAttribute(
        "data-src",
        "/custom.png"
      );
    });

    it("passes className to custom component", () => {
      const CustomImage = ({ className, ...props }: any) => (
        <img data-testid="custom-img" className={className} {...props} />
      );
      render(
        <Image as={CustomImage} src="/img.png" alt="Cls" className="rounded" />
      );
      const img = screen.getByTestId("custom-img");
      expect(img).toHaveClass("rounded");
    });

    it("passes all props to custom component", () => {
      const CustomImage = (props: any) => (
        <img
          data-testid="custom-img"
          data-fill={props.fill?.toString()}
          data-priority={props.priority?.toString()}
          src={props.src}
          alt={props.alt}
        />
      );
      render(
        <Image
          as={CustomImage}
          src="/img.png"
          alt="Props test"
          fill={true}
          priority={true}
        />
      );
      const img = screen.getByTestId("custom-img");
      expect(img).toHaveAttribute("data-fill", "true");
      expect(img).toHaveAttribute("data-priority", "true");
    });

    it("does not render native img when as prop is provided", () => {
      const CustomImage = (props: any) => (
        <div data-testid="custom-wrapper">{props.alt}</div>
      );
      render(<Image as={CustomImage} src="/img.png" alt="No native" />);
      expect(screen.queryByRole("img")).not.toBeInTheDocument();
    });

    it("renders forwardRef component via as prop", () => {
      const ForwardRefImage = forwardRef<HTMLImageElement, ImageComponentProps>(
        function ForwardRefImage(props, fwdRef) {
          return <img ref={fwdRef} data-testid="fwdref-img" {...props} />;
        }
      );
      render(
        <Image as={ForwardRefImage} src="/img.png" alt="ForwardRef test" />
      );
      expect(screen.getByTestId("fwdref-img")).toBeInTheDocument();
    });
  });

  describe("edge cases", () => {
    it("renders with empty alt for decorative images", () => {
      const { container } = render(<Image src="/decorative.png" alt="" />);
      const img = container.querySelector("img");
      expect(img).toHaveAttribute("alt", "");
    });

    it("renders with no className (defaults to empty string)", () => {
      const { container } = render(<Image src="/img.png" alt="No class" />);
      const img = container.querySelector("img");
      expect(img).toBeInTheDocument();
    });
  });
});
