/*
Conformance tests for the Link component:
- HTML Validation:
  - Validates HTML for anchor and button links.
  - Validates HTML for external link attributes (target, rel).
  - Validates all color variants and inverse styling.
  - Validates complex nested content.
- Accessibility:
  - Checks for no accessibility violations for basic, button, external, color variant, and inverse links.
  - Checks for no violations with custom attributes and keyboard navigation.
- Semantic HTML:
  - Ensures correct semantic roles for anchor and button.
  - Maintains semantic meaning with custom attributes.
- Cross-browser Compatibility:
  - Renders consistently across different prop combinations.
  - Handles various href formats correctly (relative, absolute, mailto, anchor).
- Performance and Best Practices:
  - Renders efficiently with minimal DOM nodes.
  - Does not create unnecessary wrapper elements.
*/
import { render, screen } from "@testing-library/react";
import { axe } from "vitest-axe";
import "@testing-library/jest-dom/vitest";

import { Link } from "../";

describe("Link Conformance Tests", () => {
  describe("HTML Validation", () => {
    it("is valid HTML with anchor link", () => {
      const { container } = render(<Link href="#">Valid anchor link</Link>);
      expect(container).toHTMLValidate();
    });
    it("is valid HTML with button link", () => {
      const { container } = render(
        <Link tag="button" type="button">
          Valid button link
        </Link>,
      );
      expect(container).toHTMLValidate();
    });
    it("is valid HTML with external link attributes", () => {
      const { container } = render(
        <Link
          href="https://example.com"
          target="_blank"
          rel="noopener noreferrer"
        >
          External link
        </Link>,
      );
      expect(container).toHTMLValidate();
    });
    it("is valid HTML with underline", () => {
      const { container } = render(
        <>
          <Link href="#" isUnderline>
            Underlined link
          </Link>
        </>,
      );
      expect(container).toHTMLValidate();
    });
    it("is valid HTML with complex nested content", () => {
      const { container } = render(
        <Link href="#">
          <span>Nested</span>
          <strong>Content</strong>
          <em>With</em>
          <div>Multiple Elements</div>
        </Link>,
      );
      expect(container).toHTMLValidate();
    });
  });

  describe("Accessibility", () => {
    it("has no accessibility violations for basic link", async () => {
      const { container } = render(<Link href="#">Accessible link</Link>);
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it("has no accessibility violations for button link", async () => {
      const { container } = render(<Link tag="button">Accessible button</Link>);
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it("has no accessibility violations for external link", async () => {
      const { container } = render(
        <Link
          href="https://example.com"
          target="_blank"
          rel="noopener noreferrer"
          aria-label="External link to example.com"
        >
          External link
        </Link>,
      );
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it("has no accessibility violations for all color variants", async () => {
      const { container } = render(
        <div>
          <Link href="#" color="default">
            Default link
          </Link>
          <Link href="#" color="orange">
            Orange link
          </Link>
          <Link href="#" color="black">
            Black link
          </Link>
        </div>,
      );
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it("has no accessibility violations for links with custom attributes", async () => {
      const { container } = render(
        <div>
          <Link href="#" aria-describedby="description">
            Link with description
          </Link>
          <div id="description">This link has a description</div>
          <Link href="#" aria-expanded="false">
            Collapsible link
          </Link>
        </div>,
      );
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it("has no accessibility violations for keyboard navigation", async () => {
      const { container } = render(
        <div>
          <Link href="#" tabIndex={0}>
            First link
          </Link>
          <Link href="#" tabIndex={0}>
            Second link
          </Link>
          <Link href="#" tabIndex={0}>
            Third link
          </Link>
        </div>,
      );
      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });
  });

  describe("Semantic HTML", () => {
    it("renders anchor element with correct semantic role", () => {
      render(<Link href="/test">Semantic link</Link>);
      const link = screen.getByRole("link");
      expect(link).toBeInTheDocument();
      expect(link.tagName).toBe("A");
    });

    it("renders button element with correct semantic role", () => {
      render(<Link tag="button">Semantic button</Link>);
      const button = screen.getByRole("button");
      expect(button).toBeInTheDocument();
      expect(button.tagName).toBe("BUTTON");
    });

    it("maintains semantic meaning with custom attributes", () => {
      render(
        <Link
          href="/test"
          aria-label="Custom label"
          aria-describedby="desc"
          data-testid="semantic-link"
        >
          Semantic link
        </Link>,
      );

      const link = screen.getByTestId("semantic-link");
      expect(link).toHaveAttribute("aria-label", "Custom label");
      expect(link).toHaveAttribute("aria-describedby", "desc");
      expect(link).toHaveAttribute("href", "/test");
    });
  });

  describe("Cross-browser Compatibility", () => {
    it("renders consistently across different prop combinations", () => {
      const testCases = [
        { href: "/", color: "default" },
        { href: "/", color: "orange" },
        { href: "/", color: "black" },
        { tag: "button", type: "button", color: "default" },
        { tag: "button", type: "button", color: "orange" },
      ];

      testCases.forEach((props, index) => {
        const { container } = render(
          <Link key={index} {...props} data-testid={`link-${index}`}>
            Test link {index}
          </Link>,
        );

        expect(container).toHTMLValidate();
        expect(screen.getByTestId(`link-${index}`)).toBeInTheDocument();
      });
    });

    it("handles various href formats correctly", () => {
      const hrefFormats = [
        "/relative-path",
        "https://example.com",
        "mailto:test@example.com",
        "#anchor",
      ];

      hrefFormats.forEach((href, index) => {
        const { container } = render(
          <Link key={index} href={href} data-testid={`link-${index}`}>
            {href} link
          </Link>,
        );

        expect(container).toHTMLValidate();
        const link = screen.getByTestId(`link-${index}`);
        expect(link).toHaveAttribute("href", href);
      });
    });
  });

  describe("Performance and Best Practices", () => {
    it("renders efficiently with minimal DOM nodes", () => {
      const { container } = render(
        <Link href="/test" className="test-class">
          Simple link
        </Link>,
      );

      // Should only have one main element
      const linkElements = container.querySelectorAll("a");
      expect(linkElements).toHaveLength(1);
    });

    it("does not create unnecessary wrapper elements", () => {
      const { container } = render(
        <Link href="/test">
          <span>Content</span>
        </Link>,
      );

      // Should have one anchor with one span child
      const link = container.querySelector("a");
      const span = container.querySelector("span");
      expect(link).toBeInTheDocument();
      expect(span).toBeInTheDocument();
      expect(link).toContainElement(span);
    });
  });
});
