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

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

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

// Mock next/link
jest.mock("next/link", () => {
  const ReactModule = require("react");
  const MockLink = ReactModule.forwardRef(
    (
      { children, href, className, onClick, ...rest }: any,
      ref: React.Ref<HTMLAnchorElement>
    ) => (
      <a
        ref={ref}
        href={href}
        className={className}
        onClick={onClick}
        data-mock="next-link"
        {...rest}
      >
        {children}
      </a>
    )
  );
  MockLink.displayName = "MockNextLink";
  return MockLink;
});

describe("Link", () => {
  describe("Rendering", () => {
    it("renders children content", () => {
      render(<Link href="/test">Click me</Link>);
      expect(screen.getByText("Click me")).toBeInTheDocument();
    });

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

    it("renders as a Next.js Link for internal links", () => {
      render(<Link href="/internal">Internal</Link>);
      const el = screen.getByText("Internal");
      expect(el.closest("a")).toHaveAttribute("href", "/internal");
    });

    it("renders as <a> for external links", () => {
      render(
        <Link href="https://example.com" external={true}>
          External
        </Link>
      );
      const el = screen.getByText("External");
      expect(el.closest("a")).toHaveAttribute("href", "https://example.com");
    });

    it("renders as <a> for http links even without external prop", () => {
      render(<Link href="https://example.com">Auto External</Link>);
      const el = screen.getByText("Auto External");
      expect(el.closest("a")).toHaveAttribute("href", "https://example.com");
    });
  });

  describe("Variants", () => {
    it("applies unstyled variant with no extra classes", () => {
      render(
        <Link href="/test" variant="unstyled">
          Unstyled
        </Link>
      );
      const el = screen.getByText("Unstyled").closest("a");
      expect(el?.className).toContain("link--unstyled");
    });

    it("applies default variant classes", () => {
      render(
        <Link href="/test" variant="default">
          Default
        </Link>
      );
      const el = screen.getByText("Default").closest("a");
      expect(el?.className).toContain("link--default");
      expect(el?.className).toContain("underline");
    });
  });

  describe("Disabled state", () => {
    it("adds disabled class when disabled", () => {
      render(
        <Link href="/test" disabled={true}>
          Disabled
        </Link>
      );
      const el = screen.getByText("Disabled").closest("a");
      expect(el?.className).toContain("link--disabled");
    });

    it("sets aria-disabled when disabled", () => {
      render(
        <Link href="/test" disabled={true} external={true}>
          Disabled
        </Link>
      );
      const el = screen.getByText("Disabled").closest("a");
      expect(el).toHaveAttribute("aria-disabled", "true");
    });

    it("sets tabIndex -1 when disabled", () => {
      render(
        <Link href="/test" disabled={true} external={true}>
          Disabled
        </Link>
      );
      const el = screen.getByText("Disabled").closest("a");
      expect(el).toHaveAttribute("tabindex", "-1");
    });

    it("applies disabled accessibility attributes on internal links", () => {
      render(
        <Link href="/test" disabled={true}>
          Disabled
        </Link>
      );
      const el = screen.getByText("Disabled").closest("a");
      // disabled links render as a plain <a>, not via next/link
      expect(el).not.toHaveAttribute("data-mock", "next-link");
      expect(el).toHaveAttribute("aria-disabled", "true");
      expect(el).toHaveAttribute("tabindex", "-1");
      expect(el).not.toHaveAttribute("href");
    });

    it("prevents click when disabled", () => {
      const onClick = jest.fn();
      render(
        <Link href="/test" disabled={true} external={true} onClick={onClick}>
          Disabled
        </Link>
      );
      const el = screen.getByText("Disabled").closest("a")!;
      fireEvent.click(el);
      expect(onClick).not.toHaveBeenCalled();
    });
  });

  describe("External links", () => {
    it("adds target=_blank for external links", () => {
      render(
        <Link href="https://example.com" external={true}>
          External
        </Link>
      );
      const el = screen.getByText("External").closest("a");
      expect(el).toHaveAttribute("target", "_blank");
    });

    it("adds rel=noopener for external links", () => {
      render(
        <Link href="https://example.com" external={true}>
          External
        </Link>
      );
      const el = screen.getByText("External").closest("a");
      expect(el).toHaveAttribute("rel", "noopener");
    });

    it("does not add target for disabled external links", () => {
      render(
        <Link href="https://example.com" external={true} disabled={true}>
          External
        </Link>
      );
      const el = screen.getByText("External").closest("a");
      expect(el).not.toHaveAttribute("target", "_blank");
    });
  });

  describe("Event handling", () => {
    it("calls onClick handler when clicked", () => {
      const onClick = jest.fn();
      render(
        <Link href="https://example.com" external={true} onClick={onClick}>
          Click
        </Link>
      );
      const el = screen.getByText("Click").closest("a")!;
      fireEvent.click(el);
      expect(onClick).toHaveBeenCalledTimes(1);
    });
  });

  describe("Ref forwarding", () => {
    it("forwards ref to the anchor element", () => {
      const ref = React.createRef<HTMLAnchorElement>();
      render(
        <Link ref={ref} href="https://test.com" external={true}>
          Ref
        </Link>
      );
      expect(ref.current).toBeInstanceOf(HTMLAnchorElement);
    });

    it("forwards ref to the anchor element for internal (next/link) links", () => {
      const ref = React.createRef<HTMLAnchorElement>();
      render(
        <Link ref={ref} href="/internal">
          Internal Ref
        </Link>
      );
      expect(ref.current).toBeInstanceOf(HTMLAnchorElement);
      expect(ref.current).toHaveAttribute("data-mock", "next-link");
    });
  });

  describe("Custom className and style", () => {
    it("applies custom className", () => {
      render(
        <Link href="/test" className="custom-class">
          Custom
        </Link>
      );
      const el = screen.getByText("Custom").closest("a");
      expect(el?.className).toContain("custom-class");
    });

    it("applies inline style", () => {
      render(
        <Link href="https://test.com" external={true} style={{ color: "red" }}>
          Styled
        </Link>
      );
      const el = screen.getByText("Styled").closest("a")!;
      expect(el.style.color).toBe("red");
    });
  });
});
