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

import React from "react";
import { ProductCardCarousel, TabSwitch, TestimonialCarousel } from "./helper";
import {
  CarouselWithProductCards,
  CarouselWithTestimonialCards,
} from "./types";

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

// Mock sub-components
jest.mock("@shared/components/button", () => ({
  Button: ({ children, onClick, ...props }: any) => (
    <button onClick={onClick} {...props}>
      {children}
    </button>
  ),
}));

jest.mock("@shared/components/material-icon", () => ({
  MaterialIcon: ({ name }: any) => (
    <span data-testid={`icon-${name}`}>{name}</span>
  ),
}));

jest.mock("@shared/contentful/blocks/cards/product-card", () => ({
  ProductCard: ({
    planName,
    speed,
    onCtaClick,
    onToggleExpand,
    isExpanded,
  }: any) => (
    <div
      data-testid="product-card"
      data-plan={planName}
      data-speed={speed}
      data-expanded={isExpanded}
    >
      {planName}
      <button onClick={onCtaClick} data-testid="product-cta">
        CTA
      </button>
      <button onClick={onToggleExpand} data-testid="product-toggle">
        Toggle
      </button>
    </div>
  ),
}));

jest.mock("@shared/contentful/blocks/cards/testimonial-card", () => ({
  TestimonialCard: ({ title, isActive }: any) => (
    <div
      data-testid="testimonial-card"
      data-active={isActive}
      data-title={title}
    >
      {title}
    </div>
  ),
}));

jest.mock("@shared/hooks/use-carousel-swipe", () => ({
  useCarouselSwipe: () => ({
    currentIndex: 0,
    swipeOffset: 0,
    isSwiping: false,
    isMobile: false,
    containerWidth: 1024,
    containerRef: { current: null },
    handleTouchStart: jest.fn(),
    handleTouchMove: jest.fn(),
    handleTouchEnd: jest.fn(),
    prevSlide: jest.fn(),
    nextSlide: jest.fn(),
    goToSlide: jest.fn(),
    constants: { CARD_OFFSET_PERCENTAGE: 105 },
  }),
}));

jest.mock("@shared/utils", () => ({
  cx: (...args: any[]) => args.filter(Boolean).join(" "),
}));

describe("ProductCardCarousel", () => {
  beforeEach(() => {
    Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
      configurable: true,
      get: () => 900,
    });
  });
  const createProductFields = (
    items: any[] = []
  ): CarouselWithProductCards => ({
    __typename: "ComponentCarousel",
    sys: { id: "test-carousel" },
    title: "Product Carousel",
    items: { items },
  });

  const sampleProduct = {
    __typename: "ComponentProductCard" as const,
    sys: { id: "prod-1" },
    speed: "500 Mbps|Fast internet",
    price: "49",
    priceSuffix: "99/mo",
    techType: "Fiber",
    highlighted: false,
    productCardDescription: "Great plan",
    benefitsTitle: "Benefits",
    benefitsExpanded: false,
    innerBadge: "New",
    benefits: { items: [{ text: "Benefit 1" }] },
    giftRewards: { list: { items: [{ text: "Gift" }] } },
    cta: { buttonLabel: "Select" },
    innerBadgeIcon: { url: "https://example.com/icon.png" },
  };

  it("returns null when no items and no title", () => {
    const fields = createProductFields([]);
    fields.title = undefined;
    const { container } = render(<ProductCardCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("returns null when items is undefined", () => {
    const fields = {
      __typename: "ComponentCarousel" as const,
      sys: { id: "test" },
      items: { items: undefined as any },
      title: undefined,
    } as any;
    const { container } = render(<ProductCardCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("renders product cards when items exist", () => {
    const fields = createProductFields([sampleProduct]);
    render(<ProductCardCarousel fields={fields} />);
    expect(screen.getAllByTestId("product-card")).toHaveLength(1);
  });

  it("renders non-carousel layout for 2 or fewer items", () => {
    const fields = createProductFields([
      sampleProduct,
      { ...sampleProduct, sys: { id: "prod-2" } },
    ]);
    const { container } = render(<ProductCardCarousel fields={fields} />);
    // Non-carousel: wrapped in flex layout
    expect(container.querySelector(".flex.w-full")).toBeInTheDocument();
  });

  it("renders carousel layout for more than 2 items", () => {
    const items = Array.from({ length: 4 }, (_, i) => ({
      ...sampleProduct,
      sys: { id: `prod-${i}` },
    }));
    const fields = createProductFields(items);
    const { container } = render(<ProductCardCarousel fields={fields} />);
    // Should have mobile stack view (flex-col for md:hidden)
    expect(container.querySelector(".flex-col")).toBeInTheDocument();
  });

  it("parses speed field correctly (planName | planSubtext)", () => {
    const fields = createProductFields([sampleProduct]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toHaveAttribute("data-plan", "500 Mbps");
    expect(card).toHaveAttribute("data-speed", "500 Mbps|Fast internet");
  });

  it("handles missing speed gracefully", () => {
    const item = { ...sampleProduct, speed: undefined };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toHaveAttribute("data-plan", "");
  });

  it("handles item with all optional fields missing", () => {
    const minimalItem = {
      __typename: "ComponentProductCard" as const,
      sys: { id: "minimal" },
    };
    const fields = createProductFields([minimalItem]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toBeInTheDocument();
  });

  it("handles item with empty benefits and giftRewards", () => {
    const item = {
      ...sampleProduct,
      benefits: undefined,
      giftRewards: undefined,
      innerBadge: undefined,
      innerBadgeIcon: undefined,
      priceSuffix: undefined,
      price: undefined,
      cta: undefined,
    };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toBeInTheDocument();
  });

  it("handles speed without pipe separator", () => {
    const item = { ...sampleProduct, speed: "500 Mbps" };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toHaveAttribute("data-plan", "500 Mbps");
  });

  it("renders Next arrow and hides Previous on first slide in carousel mode", async () => {
    const items = Array.from({ length: 4 }, (_, i) => ({
      ...sampleProduct,
      sys: { id: `prod-${i}` },
    }));
    const fields = createProductFields(items);
    render(<ProductCardCarousel fields={fields} />);

    fireEvent(window, new Event("resize"));

    await waitFor(() =>
      expect(screen.getByLabelText("Next")).toBeInTheDocument()
    );
    expect(screen.queryByLabelText("Previous")).not.toBeInTheDocument();
  });

  it("shows Previous after moving forward, then hides it after returning to first slide", async () => {
    const items = Array.from({ length: 4 }, (_, i) => ({
      ...sampleProduct,
      sys: { id: `prod-${i}` },
    }));
    const fields = createProductFields(items);
    render(<ProductCardCarousel fields={fields} />);

    fireEvent(window, new Event("resize"));

    const nextBtn = await screen.findByLabelText("Next");
    fireEvent.click(nextBtn);

    const prevBtn = await screen.findByLabelText("Previous");
    expect(prevBtn).toBeInTheDocument();

    fireEvent.click(prevBtn);

    expect(screen.queryByLabelText("Previous")).not.toBeInTheDocument();
  });

  it("calls nextSlide on Next button click", async () => {
    const items = Array.from({ length: 4 }, (_, i) => ({
      ...sampleProduct,
      sys: { id: `prod-${i}` },
    }));
    const fields = createProductFields(items);
    render(<ProductCardCarousel fields={fields} />);

    fireEvent(window, new Event("resize"));

    const nextBtn = await screen.findByLabelText("Next");
    fireEvent.click(nextBtn);

    expect(nextBtn).toBeInTheDocument();
  });

  it("handles toggle expand click for desktop (non-carousel) cards", () => {
    const fields = createProductFields([
      sampleProduct,
      { ...sampleProduct, sys: { id: "prod-2" } },
    ]);
    render(<ProductCardCarousel fields={fields} />);
    const toggleButtons = screen.getAllByTestId("product-toggle");
    // Click desktop toggle
    fireEvent.click(toggleButtons[0]);
    // No error - toggle state changes internally
    expect(toggleButtons[0]).toBeInTheDocument();
  });

  it("handles CTA click on product card", () => {
    const fields = createProductFields([sampleProduct]);
    render(<ProductCardCarousel fields={fields} />);
    const ctaButton = screen.getByTestId("product-cta");
    fireEvent.click(ctaButton);
    // handleCtaClick just returns; no error
    expect(ctaButton).toBeInTheDocument();
  });

  it("handles toggle expand for mobile cards in carousel mode", () => {
    const items = Array.from({ length: 4 }, (_, i) => ({
      ...sampleProduct,
      sys: { id: `prod-${i}` },
    }));
    const fields = createProductFields(items);
    render(<ProductCardCarousel fields={fields} />);
    // Mobile view cards are in the flex-col hidden section
    const toggleButtons = screen.getAllByTestId("product-toggle");
    // The first set of cards are in mobile view (first 4 items)
    fireEvent.click(toggleButtons[0]);
    expect(toggleButtons[0]).toBeInTheDocument();
  });

  it("renders with benefitsExpanded true in fields", () => {
    const item = { ...sampleProduct, benefitsExpanded: true };
    const fields = createProductFields([item, { ...item, sys: { id: "p2" } }]);
    render(<ProductCardCarousel fields={fields} />);
    // Cards should render with expanded state
    const cards = screen.getAllByTestId("product-card");
    expect(cards[0]).toHaveAttribute("data-expanded", "true");
  });

  it("renders when title exists but items are empty", () => {
    const fields = createProductFields([]);
    fields.title = "Has Title";
    const { container } = render(<ProductCardCarousel fields={fields} />);
    // Should NOT return null because title exists
    expect(container.firstChild).not.toBeNull();
  });

  it("handles highlighted item (truthy branch)", () => {
    const item = {
      ...sampleProduct,
      highlighted: true,
      topBadgeText: "Best Deal",
    };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toBeInTheDocument();
  });

  it("handles item with giftRewards.list but no items", () => {
    const item = {
      ...sampleProduct,
      giftRewards: { list: { items: undefined as any } },
    };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    const card = screen.getByTestId("product-card");
    expect(card).toBeInTheDocument();
  });

  it("handles item with giftRewards but no list", () => {
    const item = {
      ...sampleProduct,
      giftRewards: { list: undefined as any },
    };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    expect(screen.getByTestId("product-card")).toBeInTheDocument();
  });

  it("handles item with priceSuffix without slash", () => {
    const item = { ...sampleProduct, priceSuffix: "99" };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    expect(screen.getByTestId("product-card")).toBeInTheDocument();
  });

  it("handles item with innerBadgeIcon but no url", () => {
    const item = {
      ...sampleProduct,
      innerBadgeIcon: {} as any,
    };
    const fields = createProductFields([item]);
    render(<ProductCardCarousel fields={fields} />);
    expect(screen.getByTestId("product-card")).toBeInTheDocument();
  });

  it("handles fields with items but items.items is null", () => {
    const fields = {
      __typename: "ComponentCarousel" as const,
      sys: { id: "test" },
      items: { items: null as any },
      title: "Title present",
    } as any;
    const { container } = render(<ProductCardCarousel fields={fields} />);
    // title exists so it does not return null but items array is empty
    expect(container.firstChild).not.toBeNull();
  });

  it("handles fields with no items property at all", () => {
    const fields = {
      __typename: "ComponentCarousel" as const,
      sys: { id: "test" },
      items: undefined as any,
      title: undefined,
    } as any;
    const { container } = render(<ProductCardCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("renders tabbed view when tabs and activeTab are provided", () => {
    const items = [
      { ...sampleProduct, sys: { id: "prod-1" }, productCategory: "Internet" },
      { ...sampleProduct, sys: { id: "prod-2" }, productCategory: "Phone" },
    ];
    const fields = createProductFields(items);
    const { container } = render(
      <ProductCardCarousel
        fields={fields}
        tabs={["Internet", "Phone"]}
        activeTab="Internet"
      />
    );
    // Should render tab containers with display block/none
    const visibleTab = container.querySelector("[style*='display: block']");
    expect(visibleTab).toBeInTheDocument();
  });
});

describe("TestimonialCarousel", () => {
  const createTestimonialFields = (
    items: any[] = []
  ): CarouselWithTestimonialCards => ({
    __typename: "ComponentCarousel",
    sys: { id: "test-carousel" },
    title: "Testimonials",
    items: { items },
  });

  const sampleTestimonial = {
    __typename: "ComponentTestimonialCard" as const,
    sys: { id: "test-1" },
    title: "Great Service",
    author: "John Doe",
    role: "CEO",
    rating: 5,
    quote: "Amazing experience!",
  };

  it("returns null when no testimonials", () => {
    const fields = createTestimonialFields([]);
    const { container } = render(<TestimonialCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("returns null when testimonials items is undefined", () => {
    const fields = {
      __typename: "ComponentCarousel" as const,
      sys: { id: "test" },
      title: "Testimonials",
      items: { items: undefined as any },
    } as any;
    const { container } = render(<TestimonialCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("returns null when testimonials field items is null", () => {
    const fields = {
      __typename: "ComponentCarousel" as const,
      sys: { id: "test" },
      title: "Testimonials",
      items: { items: null as any },
    } as any;
    const { container } = render(<TestimonialCarousel fields={fields} />);
    expect(container.firstChild).toBeNull();
  });

  it("renders testimonial cards when items exist", () => {
    const fields = createTestimonialFields([sampleTestimonial]);
    render(<TestimonialCarousel fields={fields} />);
    expect(screen.getByTestId("testimonial-card")).toBeInTheDocument();
  });

  it("renders navigation dots for each testimonial", () => {
    const items = [
      sampleTestimonial,
      { ...sampleTestimonial, sys: { id: "test-2" }, title: "Second" },
      { ...sampleTestimonial, sys: { id: "test-3" }, title: "Third" },
    ];
    const fields = createTestimonialFields(items);
    render(<TestimonialCarousel fields={fields} />);
    const dots = screen.getAllByRole("button", { name: /Go to slide/ });
    expect(dots).toHaveLength(3);
  });

  it("renders Previous and Next navigation buttons", () => {
    const items = [
      sampleTestimonial,
      { ...sampleTestimonial, sys: { id: "test-2" } },
    ];
    const fields = createTestimonialFields(items);
    render(<TestimonialCarousel fields={fields} />);
    expect(screen.getByLabelText("Previous")).toBeInTheDocument();
    expect(screen.getByLabelText("Next")).toBeInTheDocument();
  });

  it("renders dot navigation with correct aria labels", () => {
    const items = [
      sampleTestimonial,
      { ...sampleTestimonial, sys: { id: "test-2" } },
    ];
    const fields = createTestimonialFields(items);
    render(<TestimonialCarousel fields={fields} />);
    expect(screen.getByLabelText("Go to slide 1")).toBeInTheDocument();
    expect(screen.getByLabelText("Go to slide 2")).toBeInTheDocument();
  });

  it("calls goToSlide when dot is clicked", () => {
    const items = [
      sampleTestimonial,
      { ...sampleTestimonial, sys: { id: "test-2" } },
      { ...sampleTestimonial, sys: { id: "test-3" } },
    ];
    const fields = createTestimonialFields(items);
    render(<TestimonialCarousel fields={fields} />);
    const dot2 = screen.getByLabelText("Go to slide 2");
    fireEvent.click(dot2);
    expect(dot2).toBeInTheDocument();
  });
});

describe("TabSwitch", () => {
  const defaultTabProps = {
    tabs: ["Tab A", "Tab B", "Tab C"],
    activeTab: "Tab A",
    onChange: jest.fn(),
  };

  it("renders all tabs", () => {
    render(<TabSwitch {...defaultTabProps} />);
    expect(screen.getByText("Tab A")).toBeInTheDocument();
    expect(screen.getByText("Tab B")).toBeInTheDocument();
    expect(screen.getByText("Tab C")).toBeInTheDocument();
  });

  it("calls onChange when a tab is clicked", () => {
    const onChange = jest.fn();
    render(<TabSwitch {...defaultTabProps} onChange={onChange} />);
    fireEvent.click(screen.getByText("Tab B"));
    expect(onChange).toHaveBeenCalledWith("Tab B");
  });

  it("applies active style to selected tab", () => {
    render(<TabSwitch {...defaultTabProps} />);
    const activeBtn = screen.getByText("Tab A");
    expect(activeBtn.className).toContain("text-text-inverse");
  });

  it("applies inactive style to non-selected tabs", () => {
    render(<TabSwitch {...defaultTabProps} />);
    const inactiveBtn = screen.getByText("Tab B");
    expect(inactiveBtn.className).toContain("text-text-disabled");
  });

  it("applies custom className", () => {
    const { container } = render(
      <TabSwitch {...defaultTabProps} className="custom-class" />
    );
    expect(container.innerHTML).toContain("custom-class");
  });

  it("renders sliding indicator", () => {
    const { container } = render(<TabSwitch {...defaultTabProps} />);
    const indicator = container.querySelector(".bg-bg-fill-brand");
    expect(indicator).toBeInTheDocument();
  });
});
