import React from "react";
import { PrimaryHero } from "./index";

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

jest.mock("@shared/components/checklist", () => ({
  Checklist: ({ items }: any) => (
    <ul data-testid="checklist">
      {items?.map((i: string, idx: number) => (
        <li key={idx}>{i}</li>
      ))}
    </ul>
  ),
}));

jest.mock("@shared/components/next-image", () => ({
  NextImage: ({ src, alt, className }: any) => (
    <img data-testid="next-image" src={src} alt={alt} className={className} />
  ),
}));

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

jest.mock("@shared/contentful/blocks/button", () => ({
  Button: ({
    children,
    buttonLabel,
    linkClassName,
    buttonClassName,
    ...rest
  }: any) => (
    <button data-testid="button" className={buttonClassName || linkClassName}>
      {children || buttonLabel || rest.label}
    </button>
  ),
}));

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

const baseProps = { title: "Fast Internet" };

describe("PrimaryHero", () => {
  beforeEach(() => jest.clearAllMocks());

  it("renders title as h2 by default", () => {
    render(<PrimaryHero {...baseProps} />);
    expect(screen.getByText("Fast Internet").tagName).toBe("H2");
  });

  it("renders title as h1 when showAsHeading is true", () => {
    render(<PrimaryHero {...baseProps} showAsHeading={true} />);
    expect(screen.getByText("Fast Internet").tagName).toBe("H1");
  });

  it("does not render title section when title is empty", () => {
    render(<PrimaryHero {...baseProps} title="" />);
    expect(screen.queryByRole("heading")).not.toBeInTheDocument();
  });

  it("renders subtitle when provided", () => {
    render(<PrimaryHero {...baseProps} subTitle="Super fast speeds" />);
    expect(screen.getByText("Super fast speeds")).toBeInTheDocument();
  });

  it("does not render subtitle when not provided", () => {
    const { container } = render(<PrimaryHero {...baseProps} />);
    expect(container.querySelectorAll("p.subheading3")).toHaveLength(0);
  });

  describe("Price section", () => {
    it("renders price with dollar sign", () => {
      render(<PrimaryHero {...baseProps} price="49.99" />);
      expect(screen.getByText("$")).toBeInTheDocument();
      expect(screen.getByText("49.99")).toBeInTheDocument();
    });

    it("renders priceSuffix when provided", () => {
      render(<PrimaryHero {...baseProps} price="30" priceSuffix="/mo" />);
      expect(screen.getByText("/mo")).toBeInTheDocument();
    });

    it("does not render priceSuffix when not provided", () => {
      render(<PrimaryHero {...baseProps} price="30" />);
      expect(screen.queryByText("/mo")).not.toBeInTheDocument();
    });

    it("renders priceCallout split by pipe", () => {
      render(
        <PrimaryHero
          {...baseProps}
          price="50"
          priceCallout="Starting at|per month"
        />
      );
      expect(screen.getByText("Starting at")).toBeInTheDocument();
      expect(screen.getByText("per month")).toBeInTheDocument();
    });

    it("does not render priceCallout when not provided", () => {
      render(<PrimaryHero {...baseProps} price="50" />);
      expect(screen.queryByText("Starting at")).not.toBeInTheDocument();
    });

    it("does not render price section when price is not provided", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByText("$")).not.toBeInTheDocument();
    });
  });

  describe("Checklist", () => {
    it("renders checklist when provided", () => {
      const checklist = [{ title: "No data caps" }, { title: "Free install" }];
      render(<PrimaryHero {...baseProps} checklist={checklist} />);
      expect(screen.getByTestId("checklist")).toBeInTheDocument();
      expect(screen.getByText("No data caps")).toBeInTheDocument();
      expect(screen.getByText("Free install")).toBeInTheDocument();
    });

    it("does not render checklist when not provided", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByTestId("checklist")).not.toBeInTheDocument();
    });
  });

  describe("Primary CTA", () => {
    it("renders primaryCta1 button", () => {
      render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Get Started", href: "/start" }}
        />
      );
      expect(screen.getByText("Get Started")).toBeInTheDocument();
    });

    it("hides primaryCta1 on mobile when hideOnMobileCta1 is true", () => {
      const { container } = render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Go" }}
          hideOnMobileCta1={true}
        />
      );
      const ctaWrapper = container.querySelector(".hidden.md\\:block");
      expect(ctaWrapper).toBeInTheDocument();
    });

    it("does not render primaryCta1 when not provided", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByText("Get Started")).not.toBeInTheDocument();
    });

    it("renders both CTAs side by side when both are button type", () => {
      const { container } = render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Check plans", showButtonAs: "solid" }}
          primaryCta2={{
            buttonLabel: "Shop AT&T deals",
            showButtonAs: "solid",
          }}
        />
      );
      expect(screen.getByText("Check plans")).toBeInTheDocument();
      expect(screen.getByText("Shop AT&T deals")).toBeInTheDocument();
      const row = container.querySelector(".sm\\:flex-row");
      expect(row).toBeInTheDocument();
    });

    it("renders CTAs stacked when only primaryCta1 is present", () => {
      const { container } = render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Check plans", showButtonAs: "solid" }}
        />
      );
      expect(screen.getByText("Check plans")).toBeInTheDocument();
      expect(container.querySelector(".sm\\:flex-row")).not.toBeInTheDocument();
    });

    it("renders CTAs stacked when one CTA is not a button type", () => {
      const { container } = render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Check plans", showButtonAs: "solid" }}
          primaryCta2={{ buttonLabel: "Learn more", showButtonAs: "text" }}
        />
      );
      expect(screen.getByText("Check plans")).toBeInTheDocument();
      expect(screen.getByText("Learn more")).toBeInTheDocument();
      expect(container.querySelector(".sm\\:flex-row")).not.toBeInTheDocument();
    });

    it("hides primaryCta2 on mobile when hideOnMobileCta2 is true", () => {
      const { container } = render(
        <PrimaryHero
          {...baseProps}
          primaryCta2={{ buttonLabel: "Shop deals", showButtonAs: "solid" }}
          hideOnMobileCta2={true}
        />
      );
      const ctaWrapper = container.querySelector(".hidden.md\\:block");
      expect(ctaWrapper).toBeInTheDocument();
    });

    it("renders only primaryCta2 when primaryCta1 is not provided", () => {
      render(
        <PrimaryHero
          {...baseProps}
          primaryCta2={{ buttonLabel: "Shop deals", showButtonAs: "solid" }}
        />
      );
      expect(screen.getByText("Shop deals")).toBeInTheDocument();
    });
  });

  describe("Secondary CTA", () => {
    it("renders secondaryCtaPrefix and secondaryCta", () => {
      render(
        <PrimaryHero
          {...baseProps}
          secondaryCtaPrefix="Or"
          secondaryCta={{ buttonLabel: "Call us" }}
        />
      );
      expect(screen.getAllByText("Or").length).toBeGreaterThan(0);
      expect(screen.getAllByText("Call us").length).toBeGreaterThan(0);
    });

    it("renders only secondaryCtaPrefix without secondaryCta", () => {
      render(<PrimaryHero {...baseProps} secondaryCtaPrefix="Or" />);
      expect(screen.getAllByText("Or").length).toBeGreaterThan(0);
    });

    it("renders only secondaryCta without prefix", () => {
      render(
        <PrimaryHero {...baseProps} secondaryCta={{ buttonLabel: "Call us" }} />
      );
      expect(screen.getAllByText("Call us").length).toBeGreaterThan(0);
    });

    it("does not render secondary section when neither provided", () => {
      const { container } = render(<PrimaryHero {...baseProps} />);
      expect(container.querySelectorAll(".md\\:flex")).toHaveLength(0);
    });
  });

  describe("Bottom link", () => {
    it("renders bottom link when buttonLabel and href exist", () => {
      render(
        <PrimaryHero
          {...baseProps}
          bottomLink={{ buttonLabel: "Learn more", href: "/learn" }}
        />
      );
      expect(screen.getAllByText("Learn more").length).toBeGreaterThan(0);
    });

    it("renders bottom link when only href exists (label is from label prop)", () => {
      render(
        <PrimaryHero
          {...baseProps}
          bottomLink={{ label: "Details", href: "/details" }}
        />
      );
      expect(screen.getAllByText("Details").length).toBeGreaterThan(0);
    });

    it("does not render bottom link when no label and no href", () => {
      render(<PrimaryHero {...baseProps} bottomLink={{}} />);
      // No button rendered for bottom link
      expect(screen.queryAllByTestId("button")).toHaveLength(0);
    });

    it("does not render bottom link when bottomLink is undefined", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByText("Learn more")).not.toBeInTheDocument();
    });
  });

  describe("Pricing description disclaimer", () => {
    it("renders pricingDescription with subheading and responsive alignment classes", () => {
      render(
        <PrimaryHero
          {...baseProps}
          pricingDescription="Building a new home? Contact us to see if you're eligible for Kinetic Internet."
        />
      );

      const pricingText = screen.getByText(
        "Building a new home? Contact us to see if you're eligible for Kinetic Internet."
      );

      expect(pricingText).toBeInTheDocument();
      expect(pricingText).toHaveClass("subheading1");
      expect(pricingText).toHaveClass(
        "text-left",
        "sm:text-center",
        "xl:text-left"
      );
    });

    it("renders pricingDescriptionDisclaimer (desktop and mobile)", () => {
      render(
        <PrimaryHero
          {...baseProps}
          pricingDescriptionDisclaimer="Taxes apply"
        />
      );
      expect(screen.getAllByText("Taxes apply")).toHaveLength(1);
    });

    it("does not render disclaimer when not provided", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByText("Taxes apply")).not.toBeInTheDocument();
    });
  });
  describe("Images", () => {
    it("renders carousel image (mobile and desktop)", () => {
      render(
        <PrimaryHero
          {...baseProps}
          carouselImages={["https://img.test/hero.jpg"]}
        />
      );
      const imgs = screen.getAllByAltText("Hero");
      expect(imgs).toHaveLength(2);
      expect(imgs[0]).toHaveAttribute("src", "https://img.test/hero.jpg");
    });

    it("does not render carousel image when empty array", () => {
      render(<PrimaryHero {...baseProps} carouselImages={[]} />);
      expect(screen.queryByAltText("Hero")).not.toBeInTheDocument();
    });

    it("renders badge image (mobile and desktop)", () => {
      render(
        <PrimaryHero {...baseProps} badgeImage="https://img.test/badge.png" />
      );
      const badges = screen.getAllByAltText("Badge");
      expect(badges).toHaveLength(2);
    });

    it("does not render badge image when not provided", () => {
      render(<PrimaryHero {...baseProps} />);
      expect(screen.queryByAltText("Badge")).not.toBeInTheDocument();
    });

    it("renders desktop background video when heroVideo URL exists", () => {
      render(
        <PrimaryHero
          {...baseProps}
          carouselImages={["https://img.test/hero.jpg"]}
          heroVideo={{
            url: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
            title: "Desktop hero video",
          }}
        />
      );

      expect(
        screen.getByTestId("hero-background-video-desktop")
      ).toHaveAttribute("aria-label", "Desktop hero video");
      expect(screen.getAllByAltText("Hero")).toHaveLength(1);
    });

    it("falls back to images when heroVideo URL is missing", () => {
      render(
        <PrimaryHero
          {...baseProps}
          carouselImages={["https://img.test/hero.jpg"]}
          heroVideo={{ title: "Desktop hero video" }}
        />
      );

      expect(
        screen.queryByTestId("hero-background-video-desktop")
      ).not.toBeInTheDocument();
      expect(screen.getAllByAltText("Hero")).toHaveLength(2);
    });

    it("renders mobile video when heroVideoMobile URL exists", () => {
      render(
        <PrimaryHero
          {...baseProps}
          carouselImages={["https://img.test/hero.jpg"]}
          heroVideoMobile={{
            url: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
            title: "Mobile hero video",
          }}
        />
      );

      expect(screen.getByTestId("hero-video-mobile")).toHaveAttribute(
        "aria-label",
        "Mobile hero video"
      );
      expect(screen.getAllByAltText("Hero")).toHaveLength(1);
    });

    it("uses the default desktop video label when no titles are provided", () => {
      render(
        <PrimaryHero
          {...baseProps}
          title=""
          heroVideo={{
            url: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
          }}
        />
      );

      expect(
        screen.getByTestId("hero-background-video-desktop")
      ).toHaveAttribute("aria-label", "Hero background video");
    });
  });

  describe("renderCheckPlans", () => {
    it("passes renderCheckPlans to Button", () => {
      const renderFn = jest.fn();
      render(
        <PrimaryHero
          {...baseProps}
          primaryCta1={{ buttonLabel: "Go" }}
          renderCheckPlans={renderFn}
        />
      );
      expect(screen.getByText("Go")).toBeInTheDocument();
    });
  });
});
