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

describe("Loading", () => {
  // Basic rendering tests
  describe("Rendering", () => {
    it("renders loading indicator", () => {
      render(<Loading />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toBeInTheDocument();
    });

    it("renders with custom className", () => {
      render(<Loading className="custom-loading" />);
      const loadingElement = screen.getByRole("status");
      const spinner = loadingElement.querySelector("svg");
      expect(spinner).toHaveClass("custom-loading");
    });

    it("renders with text", () => {
      render(<Loading text="Loading data..." />);
      expect(screen.getByText("Loading data...")).toBeInTheDocument();
    });

    it("renders without text by default", () => {
      render(<Loading />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).not.toHaveTextContent();
    });

    it("renders different sizes", () => {
      const { rerender } = render(<Loading size="xs" />);
      let spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("w-3", "h-3");

      rerender(<Loading size="sm" />);
      spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("w-4", "h-4");

      rerender(<Loading size="md" />);
      spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("w-8", "h-8");

      rerender(<Loading size="lg" />);
      spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("w-12", "h-12");

      rerender(<Loading size="xl" />);
      spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("w-16", "h-16");
    });
  });

  // Variant tests
  describe("Variants", () => {
    it("renders spinner variant by default", () => {
      render(<Loading />);
      const spinner = screen.getByRole("status").firstChild;
      expect(spinner).toHaveClass("animate-spin");
    });

    it("renders dots variant", () => {
      render(<Loading variant="dots" />);
      const dotsContainer = screen.getByRole("status").firstChild;
      expect(dotsContainer).toHaveClass("flex", "space-x-1");

      // Should have 3 dots
      const dots = dotsContainer?.children;
      expect(dots).toHaveLength(3);
    });

    it("renders pulse variant", () => {
      render(<Loading variant="pulse" />);
      const pulseElement = screen.getByRole("status").firstChild;
      expect(pulseElement).toHaveClass("animate-pulse");
    });

    it("renders bars variant", () => {
      render(<Loading variant="bars" />);
      const barsContainer = screen.getByRole("status").firstChild;

      // Should have 4 bars
      const bars = barsContainer?.children;
      expect(bars).toHaveLength(4);
    });

    it("renders ring variant", () => {
      render(<Loading variant="ring" />);
      const ring = screen.getByRole("status").firstChild;
      expect(ring).toHaveClass("relative");
    });
  });

  // Color tests
  describe("Colors", () => {
    it("renders with primary color by default", () => {
      render(<Loading />);
      const container = screen.getByRole("status");
      expect(container).toHaveClass("text-primary");
    });

    it("renders with secondary color", () => {
      render(<Loading color="secondary" />);
      const container = screen.getByRole("status");
      expect(container).toHaveClass("text-secondary");
    });

    it("renders with muted color", () => {
      render(<Loading color="muted" />);
      const container = screen.getByRole("status");
      expect(container).toHaveClass("text-muted-foreground");
    });
  });

  // Layout tests
  describe("Layout", () => {
    it("centers loading indicator when center prop is true", () => {
      render(<Loading center />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toHaveClass("justify-center");
    });

    it("does not center by default", () => {
      render(<Loading />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).not.toHaveClass("justify-center");
    });

    it("renders as overlay when overlay prop is true", () => {
      render(<Loading overlay />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toHaveClass("fixed", "inset-0", "z-50");
    });

    it("renders normally when overlay is false", () => {
      render(<Loading overlay={false} />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).not.toHaveClass("fixed", "inset-0", "z-50");
    });
  });

  // Accessibility tests
  describe("Accessibility", () => {
    it("has proper role and ARIA attributes", () => {
      render(<Loading />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toHaveAttribute("role", "status");
      expect(loadingElement).toHaveAttribute("aria-live", "polite");
      expect(loadingElement).toHaveAttribute("aria-label", "Loading");
    });

    it("uses custom text for aria-label when provided", () => {
      render(<Loading text="Loading user data" />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toHaveAttribute("aria-label", "Loading user data");
    });

    it("announces text to screen readers", () => {
      render(<Loading text="Processing request..." />);
      const textElement = screen.getByText("Processing request...");
      expect(textElement).toBeInTheDocument();
      expect(textElement).toHaveClass("ml-2", "text-sm", "font-medium");
    });
  });

  // Animation tests
  describe("Animations", () => {
    it("has proper animation classes for spinner", () => {
      render(<Loading variant="spinner" />);
      const spinner = screen.getByRole("status").querySelector("svg");
      expect(spinner).toHaveClass("animate-spin");
    });

    it("has proper animation classes for dots", () => {
      render(<Loading variant="dots" />);
      const dotsContainer = screen.getByRole("status").firstChild;
      const dots = dotsContainer?.children;

      // Each dot should have animation style
      expect(dots?.[0]).toHaveStyle(
        "animation: loading-dots 1.4s ease-in-out 0s infinite both"
      );
      expect(dots?.[1]).toHaveStyle(
        "animation: loading-dots 1.4s ease-in-out 0.2s infinite both"
      );
      expect(dots?.[2]).toHaveStyle(
        "animation: loading-dots 1.4s ease-in-out 0.4s infinite both"
      );
    });

    it("has proper animation classes for pulse", () => {
      render(<Loading variant="pulse" />);
      const pulseElement = screen.getByRole("status").firstChild;
      expect(pulseElement).toHaveClass("animate-pulse");
    });

    it("has proper animation classes for bars", () => {
      render(<Loading variant="bars" />);
      const barsContainer = screen.getByRole("status").firstChild;
      const bars = barsContainer?.children;

      // Each bar should have scaling animation
      expect(bars?.[0]).toHaveStyle(
        "animation: loading-bars 1s ease-in-out 0s infinite"
      );
      expect(bars?.[1]).toHaveStyle(
        "animation: loading-bars 1s ease-in-out 0.1s infinite"
      );
      expect(bars?.[2]).toHaveStyle(
        "animation: loading-bars 1s ease-in-out 0.2s infinite"
      );
    });

    it("has proper animation classes for ring", () => {
      render(<Loading variant="ring" />);
      const ring = screen.getByRole("status").firstChild;
      const animatedElement = ring?.querySelector(".animate-spin");
      expect(animatedElement).toBeInTheDocument();
    });
  });

  // Edge cases
  describe("Edge cases", () => {
    it("forwards ref correctly", () => {
      const ref = React.createRef<HTMLDivElement>();
      render(<Loading ref={ref} />);
      expect(ref.current).toBeInstanceOf(HTMLDivElement);
    });

    it("handles empty text gracefully", () => {
      render(<Loading text="" />);
      const loadingElement = screen.getByRole("status");
      expect(loadingElement).toHaveAttribute("aria-label", "Loading");
    });

    it("combines multiple props correctly", () => {
      render(
        <Loading
          variant="dots"
          size="lg"
          color="secondary"
          className="custom-class"
        />
      );

      const container = screen.getByRole("status");
      expect(container).toHaveClass("text-secondary");

      const dotsContainer = container.firstChild;
      const dots = dotsContainer?.children;
      expect(dots).toHaveLength(3);
      expect(dots?.[0]).toHaveClass("w-3", "h-3", "bg-current");
    });

    it("handles multiple class names", () => {
      render(<Loading className="class1 class2" />);
      const spinner = screen.getByRole("status").querySelector("svg");
      expect(spinner).toHaveClass("class1", "class2");
    });
  });
});
