import React from "react";
import { FindKinetic } from "./index";
import { FindKineticProps } from "./types";

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

// Mock dependencies
jest.mock("@shared/components/link", () => ({
  Link: ({
    href,
    children,
    className,
  }: {
    href: string;
    children: React.ReactNode;
    className?: string;
  }) => (
    <a href={href} className={className}>
      {children}
    </a>
  ),
}));

jest.mock("@shared/components/text", () => ({
  Text: ({ as: Tag = "span", children, className }: any) => (
    <Tag className={className}>{children}</Tag>
  ),
}));

jest.mock("@shared/next", () => ({
  NextImage: ({
    src,
    alt,
    width,
    height,
  }: {
    src: string;
    alt: string;
    width: number;
    height: number;
  }) => <img src={src} alt={alt} width={width} height={height} />,
}));

const mockList = [
  { name: "New York", code: "NY" },
  { name: "California", code: "CA" },
  { name: "Texas", code: "TX" },
  { name: "Florida", code: "FL" },
  { name: "Illinois", code: "IL" },
  { name: "Ohio", code: "OH" },
  { name: "Georgia", code: "GA" },
];

const defaultProps: FindKineticProps = {
  title: "Find Kinetic Near You",
  subTitle: "Available in many locations",
  description: "Check availability in your area.",
  list: mockList,
  image: "https://example.com/image.png",
};

describe("FindKinetic", () => {
  describe("Rendering", () => {
    it("renders with default props", () => {
      render(<FindKinetic {...defaultProps} />);
      expect(screen.getByText("Find Kinetic Near You")).toBeInTheDocument();
    });

    it("renders nothing when no props are provided", () => {
      const { container } = render(<FindKinetic />);
      expect(container.firstChild).toBeInTheDocument();
    });

    it("renders title when provided", () => {
      render(<FindKinetic title="Test Title" />);
      expect(screen.getByText("Test Title")).toBeInTheDocument();
    });

    it("does not render title when not provided", () => {
      render(<FindKinetic subTitle="Sub" />);
      expect(screen.queryByText("Test Title")).not.toBeInTheDocument();
    });

    it("renders subtitle when provided", () => {
      render(<FindKinetic subTitle="Subtitle Text" />);
      expect(screen.getByText("Subtitle Text")).toBeInTheDocument();
    });

    it("does not render subtitle when not provided", () => {
      render(<FindKinetic title="Title Only" />);
      expect(screen.queryByText("Subtitle Text")).not.toBeInTheDocument();
    });

    it("renders description when provided", () => {
      render(<FindKinetic description="Desc text here" />);
      expect(screen.getByText("Desc text here")).toBeInTheDocument();
    });

    it("does not render description when not provided", () => {
      render(<FindKinetic title="Title" />);
      expect(screen.queryByText("Desc text here")).not.toBeInTheDocument();
    });
  });

  describe("Heading levels", () => {
    it("renders title as h2 when enableHeading is false", () => {
      render(<FindKinetic title="Heading Test" enableHeading={false} />);
      const el = screen.getByText("Heading Test");
      expect(el.tagName).toBe("H2");
    });

    it("renders title as h1 when enableHeading is true", () => {
      render(<FindKinetic title="Heading Test" enableHeading={true} />);
      const el = screen.getByText("Heading Test");
      expect(el.tagName).toBe("H1");
    });

    it("renders subtitle as h3 when enableHeading is false", () => {
      render(<FindKinetic subTitle="Sub Heading" enableHeading={false} />);
      const el = screen.getByText("Sub Heading");
      expect(el.tagName).toBe("H3");
    });

    it("renders subtitle as h2 when enableHeading is true", () => {
      render(<FindKinetic subTitle="Sub Heading" enableHeading={true} />);
      const el = screen.getByText("Sub Heading");
      expect(el.tagName).toBe("H2");
    });
  });

  describe("Background themes", () => {
    it("applies white background by default", () => {
      const { container } = render(<FindKinetic title="BG Test" />);
      expect(container.firstChild).toHaveClass("bg-white");
    });

    it.each([
      ["blue", "bg-[#07B2E2]"],
      ["green", "bg-[#26B170]"],
      ["yellow", "bg-[#F5FF1E]"],
      ["purple", "bg-[#931D69]"],
      ["white", "bg-white"],
      ["navy", "bg-[#00002D]"],
    ] as const)("applies %s background class", (bg, expectedClass) => {
      const { container } = render(
        <FindKinetic title="BG Test" background={bg} />
      );
      expect(container.firstChild).toHaveClass(expectedClass);
    });
  });

  describe("Color theme", () => {
    it("applies dark text color by default", () => {
      const { container } = render(<FindKinetic title="Color Test" />);
      expect(container.firstChild).toHaveClass("text-text");
    });

    it("applies light text color when color is light", () => {
      const { container } = render(
        <FindKinetic title="Color Test" color="light" />
      );
      expect(container.firstChild).toHaveClass("text-white");
    });

    it("applies dark text color when color is dark", () => {
      const { container } = render(
        <FindKinetic title="Color Test" color="dark" />
      );
      expect(container.firstChild).toHaveClass("text-text");
    });
  });

  describe("Max width", () => {
    it("applies max-w-120 class when maxWidth is true (default)", () => {
      const { container } = render(<FindKinetic title="Width Test" />);
      const innerDiv = container.firstChild?.firstChild as HTMLElement;
      expect(innerDiv).toHaveClass("max-w-120");
    });

    it("does not apply max-w-120 class when maxWidth is false", () => {
      const { container } = render(
        <FindKinetic title="Width Test" maxWidth={false} />
      );
      const innerDiv = container.firstChild?.firstChild as HTMLElement;
      expect(innerDiv).not.toHaveClass("max-w-120");
    });
  });

  describe("Location directory list", () => {
    it("renders location links from list", () => {
      render(<FindKinetic list={mockList} />);
      // Each item appears in both mobile (2-col) and desktop (3-col) lists
      const nyLinks = screen.getAllByText("New York");
      expect(nyLinks.length).toBeGreaterThanOrEqual(2);
    });

    it("generates correct href with lowercase code", () => {
      render(<FindKinetic list={[{ name: "New York", code: "NY" }]} />);
      const links = screen.getAllByText("New York");
      links.forEach(link => {
        expect(link.closest("a")).toHaveAttribute("href", "/local/ny");
      });
    });

    it("does not append a trailing slash by default", () => {
      render(<FindKinetic list={[{ name: "Alabama", code: "AL" }]} />);
      const links = screen.getAllByText("Alabama");
      links.forEach(link => {
        expect(link.closest("a")).toHaveAttribute("href", "/local/al");
      });
    });

    it("appends a trailing slash when addTrailingSlash is true", () => {
      render(
        <FindKinetic
          list={[{ name: "Alabama", code: "AL" }]}
          addTrailingSlash
        />
      );
      const links = screen.getAllByText("Alabama");
      links.forEach(link => {
        expect(link.closest("a")).toHaveAttribute("href", "/local/al/");
      });
    });

    it("does not produce a protocol-relative href when localPathPrefix is '/'", () => {
      render(
        <FindKinetic
          list={[{ name: "Alabama", code: "AL" }]}
          localPathPrefix="/"
        />
      );
      const links = screen.getAllByText("Alabama");
      links.forEach(link => {
        expect(link.closest("a")).toHaveAttribute("href", "/al");
        expect(link.closest("a")?.getAttribute("href")).not.toMatch(/^\/\//);
      });
    });

    it("sorts list items alphabetically by name", () => {
      const unsortedList = [
        { name: "Texas", code: "TX" },
        { name: "Alabama", code: "AL" },
        { name: "Michigan", code: "MI" },
      ];
      render(<FindKinetic list={unsortedList} />);
      const listItems = screen.getAllByRole("listitem");
      const texts = listItems.map(li => li.textContent);
      // In both grids, Alabama should come before Michigan, Michigan before Texas
      expect(texts[0]).toBe("Alabama");
    });

    it("does not render lists when list is empty", () => {
      render(<FindKinetic list={[]} title="No List" />);
      expect(screen.queryAllByRole("list")).toHaveLength(0);
    });

    it("does not render lists when list is not provided", () => {
      render(<FindKinetic title="No List" />);
      expect(screen.queryAllByRole("list")).toHaveLength(0);
    });

    it("renders two column layout for mobile, three for tablet and four for desktop", () => {
      const { container } = render(<FindKinetic list={mockList} />);
      const lists = container.querySelectorAll("ul");
      expect(lists).toHaveLength(3);
      expect(lists[0]).toHaveClass("grid-cols-2");
      expect(lists[1]).toHaveClass("md:grid-cols-3");
      expect(lists[2]).toHaveClass("xl:grid-cols-4");
    });

    it("rearranges items in column-major order for 2-col layout", () => {
      const list = [
        { name: "A", code: "A" },
        { name: "B", code: "B" },
        { name: "C", code: "C" },
        { name: "D", code: "D" },
      ];
      const { container } = render(<FindKinetic list={list} />);
      // Mobile list (2-col): sorted [A, B, C, D], 2 rows, column-major: A, C, B, D
      const mobileList = container.querySelector(
        "ul.grid-cols-2"
      ) as HTMLElement;
      const items = mobileList?.querySelectorAll("li");
      expect(items?.[0]?.textContent).toBe("A");
      expect(items?.[1]?.textContent).toBe("C");
      expect(items?.[2]?.textContent).toBe("B");
      expect(items?.[3]?.textContent).toBe("D");
    });
  });

  describe("Image", () => {
    it("renders image when provided", () => {
      render(<FindKinetic image="https://example.com/img.png" />);
      const img = screen.getByAltText("image");
      expect(img).toHaveAttribute("src", "https://example.com/img.png");
      expect(img).toHaveAttribute("width", "472");
    });

    it("does not render image when not provided", () => {
      render(<FindKinetic title="No Image" />);
      expect(screen.queryByAltText("image")).not.toBeInTheDocument();
    });
  });
});
