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

import { Carousel } from "../Carousel";
import { CarouselItem } from "../CarouselItem";

//items is required
describe("rendering Carousel", () => {
  describe("initial state", () => {
    it("has default class carousel", () => {
      const { getByTestId } = render(
        <Carousel data-testid="test-id" items={[]} />,
      );
      expect(getByTestId("test-id")).toHaveClass("carousel");
    });
    it("has data-carousel attribute", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(container.querySelector(".carousel")).toHaveAttribute(
        "data-carousel",
      );
    });
    it("has default class carousel__viewport-wrapper", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__viewport-wrapper").length,
      ).toBe(1);
    });
    it("has default class carousel__viewport", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__viewport").length,
      ).toBe(1);
    });
    it("has default class carousel__track", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(container.getElementsByClassName("carousel__track").length).toBe(
        1,
      );
    });
    it("does not render scrollbar by default", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__scrollbar").length,
      ).toBe(0);
    });
    it("has default class carousel__pagination", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__pagination").length,
      ).toBe(1);
    });
    it("has default class carousel__navigation", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__navigation").length,
      ).toBe(1);
    });
    it("has default class carousel__controls", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__controls").length,
      ).toBe(1);
    });
    it("has button with aria-label Naspäť", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.querySelector(`button[aria-label="Naspäť"]`),
      ).toBeInTheDocument();
    });
    it("has button with aria-label Ďalej", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.querySelector(`button[aria-label="Ďalej"]`),
      ).toBeInTheDocument();
    });
    it("button with aria-label Naspäť has default class carousel__prev", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.querySelector(`button[aria-label="Naspäť"]`),
      ).toHaveClass("carousel__prev");
    });
    it("button with aria-label Ďalej has default class carousel__next", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(container.querySelector(`button[aria-label="Ďalej"]`)).toHaveClass(
        "carousel__next",
      );
    });
    it("button with aria-label Naspäť has use element with /sprite.svg#chevron-left xlinkhref", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container
          .querySelector(`button[aria-label="Naspäť"]`)
          .querySelector("use")
          .getAttribute("xlink:href"),
      ).toBe("/sprite.svg#chevron-left");
    });
    it("button with aria-label Ďalej has use element with /sprite.svg#chevron-right xlinkhref", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container
          .querySelector(`button[aria-label="Ďalej"]`)
          .querySelector("use")
          .getAttribute("xlink:href"),
      ).toBe("/sprite.svg#chevron-right");
    });
  });
  describe("passed props", () => {
    const items = [
      <p key="item1">item1</p>,
      <p key="item2">item2</p>,
      <p key="item3">item3</p>,
    ];
    it("does not render scrollbar element without showScrollbar", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__scrollbar").length,
      ).toBe(0);
    });
    it("does not render scrollbar drag element without showScrollbar", () => {
      const { container } = render(<Carousel items={[]} />);
      expect(
        container.getElementsByClassName("carousel__scrollbar-drag").length,
      ).toBe(0);
    });
    it("renders scrollbar when showScrollbar is true", () => {
      const { container } = render(<Carousel items={items} showScrollbar />);
      expect(
        container.getElementsByClassName("carousel__scrollbar").length,
      ).toBe(1);
      expect(
        container.getElementsByClassName("carousel__scrollbar-drag").length,
      ).toBe(1);
    });
    it("does not render controls row when showScrollbar is true", () => {
      const { container } = render(<Carousel items={items} showScrollbar />);
      expect(
        container.getElementsByClassName("carousel__navigation").length,
      ).toBe(0);
      expect(
        container.getElementsByClassName("carousel__controls").length,
      ).toBe(0);
    });
    it("pagination container has role tablist", () => {
      const { container } = render(<Carousel items={items} />);
      expect(
        container.querySelector('.carousel__pagination[role="tablist"]'),
      ).toBeInTheDocument();
    });
    it("pagination container is empty initially (buttons are rendered by Swiper after initialization)", () => {
      const { container } = render(<Carousel items={items} />);
      // Pagination buttons are dynamically created by Swiper.js after initialization
      // In a test environment without DOM manipulation, they won't be present
      expect(
        container.querySelector(".carousel__pagination").children.length,
      ).toBe(0);
    });
    it("has number of CarouselItems with div with class carousel__slide equal to length of items array", () => {
      const { container } = render(<Carousel items={items} />);
      const divs = container.getElementsByClassName("carousel__slide");
      for (let i in items) {
        expect(divs[i].tagName).toBe("DIV");
      }
      expect(divs.length).toBe(3);
    });
    it("CarouselItems div has rendered item inside of itself", () => {
      const { container } = render(<Carousel items={items} />);
      const slides = container.getElementsByClassName("carousel__slide");
      for (let i = 0; i < items.length; i++) {
        expect(slides[i].querySelector("p").textContent).toBe(`item${i + 1}`);
      }
    });
    it("uses renderItems callback when provided", () => {
      const data = [{ title: "item1" }, { title: "item2" }, { title: "item3" }];
      const { container } = render(
        <Carousel
          items={data}
          renderItems={(item, index) => <p>{`${index + 1}-${item.title}`}</p>}
        />,
      );
      const slides = container.getElementsByClassName("carousel__slide");
      for (let i = 0; i < data.length; i++) {
        expect(slides[i].querySelector("p").textContent).toBe(
          `${i + 1}-${data[i].title}`,
        );
      }
    });
    it("does not double-wrap CarouselItem elements", () => {
      const items = [
        <CarouselItem key="item1" data-testid="slide-1">
          item1
        </CarouselItem>,
      ];
      const { container, getByTestId } = render(<Carousel items={items} />);

      expect(container.getElementsByClassName("carousel__slide").length).toBe(
        1,
      );
      expect(getByTestId("slide-1").textContent).toBe("item1");
    });

    it("uses Controls component defaults for built-in navigation", () => {
      const { container } = render(<Carousel items={items} />);

      expect(
        container.querySelector(
          `.carousel__prev.controls[aria-label="Naspäť"]`,
        ),
      ).toBeInTheDocument();
      expect(
        container.querySelector(`.carousel__next.controls[aria-label="Ďalej"]`),
      ).toBeInTheDocument();
    });
  });
  describe("swiperOptions prop", () => {
    const items = [
      <p key="item1">item1</p>,
      <p key="item2">item2</p>,
      <p key="item3">item3</p>,
    ];
    it("sets data-swiper-options attribute when swiperOptions prop is provided", () => {
      const swiperOptions = { slidesPerView: 2, loop: true };
      const { container } = render(
        <Carousel items={items} swiperOptions={swiperOptions} />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel.getAttribute("data-swiper-options")).toBe(
        JSON.stringify(swiperOptions),
      );
    });
    it("does not set data-swiper-options attribute when swiperOptions prop is not provided", () => {
      const { container } = render(<Carousel items={items} />);
      const carousel = container.querySelector(".carousel");
      expect(carousel.hasAttribute("data-swiper-options")).toBe(false);
    });
  });
  describe("Swiper integration", () => {
    const items = [<p key="item1">item1</p>, <p key="item2">item2</p>];

    it("track element uses carousel__track class which maps to swiper-wrapper", () => {
      const { container } = render(<Carousel items={items} />);
      expect(container.querySelector(".carousel__track")).toBeInTheDocument();
    });

    it("slide elements use carousel__slide class which maps to swiper-slide", () => {
      const { container } = render(<Carousel items={items} />);
      const slides = container.getElementsByClassName("carousel__slide");
      for (let i = 0; i < slides.length; i++) {
        expect(slides[i]).toHaveClass("carousel__slide");
      }
    });

    it("viewport element is used as Swiper container", () => {
      const { container } = render(<Carousel items={items} />);
      expect(
        container.querySelector(".carousel__viewport"),
      ).toBeInTheDocument();
    });
  });

  describe("external controls integration", () => {
    const items = [
      <p key="item1">item1</p>,
      <p key="item2">item2</p>,
      <p key="item3">item3</p>,
    ];

    it("should render with data-carousel-id when id is provided", () => {
      const { container } = render(
        <Carousel id="test-carousel" items={items} />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel).toHaveAttribute("id", "test-carousel");
    });

    it("should support external controls via data attributes", () => {
      const { container } = render(
        <div>
          <Carousel id="external-carousel" items={items} />
          <button
            data-carousel-controls="external-carousel"
            data-carousel-action="prev"
            data-testid="external-prev"
          >
            Previous
          </button>
          <button
            data-carousel-controls="external-carousel"
            data-carousel-action="next"
            data-testid="external-next"
          >
            Next
          </button>
        </div>,
      );

      const carousel = container.querySelector(".carousel");
      const prevButton = container.querySelector(
        '[data-testid="external-prev"]',
      );
      const nextButton = container.querySelector(
        '[data-testid="external-next"]',
      );

      expect(carousel).toHaveAttribute("id", "external-carousel");
      expect(prevButton).toHaveAttribute(
        "data-carousel-controls",
        "external-carousel",
      );
      expect(prevButton).toHaveAttribute("data-carousel-action", "prev");
      expect(nextButton).toHaveAttribute(
        "data-carousel-controls",
        "external-carousel",
      );
      expect(nextButton).toHaveAttribute("data-carousel-action", "next");
    });

    it("should work with both id and data-carousel-id", () => {
      const { container } = render(
        <Carousel id="test-id" data-carousel-id="test-data-id" items={items} />,
      );

      const carousel = container.querySelector(".carousel");
      expect(carousel).toHaveAttribute("id", "test-id");
      expect(carousel).toHaveAttribute("data-carousel-id", "test-data-id");
    });
  });

  describe("Auto-disable feature", () => {
    const items = [
      <p key="item1">item1</p>,
      <p key="item2">item2</p>,
      <p key="item3">item3</p>,
    ];

    it("should render carousel element with id for auto-disable feature", () => {
      const { container } = render(
        <Carousel id="auto-disable-test" items={items} />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel).toHaveAttribute("id", "auto-disable-test");
    });

    it("should support swiperOptions with slidesPerView for auto-disable", () => {
      const swiperOptions = {
        slidesPerView: 2,
        breakpoints: {
          1240: {
            slidesPerView: 3,
          },
        },
      };
      const { container } = render(
        <Carousel items={items} swiperOptions={swiperOptions} />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel.getAttribute("data-swiper-options")).toContain(
        "slidesPerView",
      );
    });

    it("should work with bleedRight carousel and auto-disable", () => {
      const { container } = render(
        <Carousel items={items} bleedRight showScrollbar />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel).toHaveClass("carousel--bleed-right");
    });

    it("should support right bleed without left bleed", () => {
      const { container } = render(
        <Carousel items={items} bleedRightNoLeft showScrollbar />,
      );
      const carousel = container.querySelector(".carousel");
      expect(carousel).toHaveClass("carousel--bleed-right-no-left");
      expect(carousel).not.toHaveClass("carousel--bleed-right");
    });

    it("should support minimal slides for testing auto-disable", () => {
      const minimalItems = [<p key="item1">item1</p>];
      const { container } = render(<Carousel items={minimalItems} />);
      const slides = container.getElementsByClassName("carousel__slide");
      expect(slides.length).toBe(1);
    });

    it("should support many slides for testing auto-disable with high slidesPerView", () => {
      const manyItems = Array.from({ length: 10 }, (_, i) => (
        <p key={`item${i}`}>item{i}</p>
      ));
      const { container } = render(<Carousel items={manyItems} />);
      const slides = container.getElementsByClassName("carousel__slide");
      expect(slides.length).toBe(10);
    });
  });
});
