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

import CartRetentionBanner from "./index";
import { TypeCartRetentionBannerFields } from "./types";

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

// Mock dependencies
jest.mock("@shared/components/text", () => ({
  Text: ({ children, ...props }: any) => <span {...props}>{children}</span>,
}));

jest.mock("@shared/contentful/blocks/button", () => ({
  Button: ({ children, onClick, buttonLabel, ...props }: any) => (
    <button onClick={onClick} data-testid="banner-button" {...props}>
      {buttonLabel || children}
    </button>
  ),
}));

jest.mock("@shared/contentful/blocks/modal", () => ({
  Modal: ({ isOpen, onRequestClose, children, ...props }: any) => (
    <div data-testid="modal" data-open={isOpen} data-type={props.type}>
      {isOpen && (
        <>
          <button data-testid="modal-close" onClick={onRequestClose}>
            Close
          </button>
          {children}
        </>
      )}
    </div>
  ),
}));

jest.mock("@shared/hooks/contentful/use-contentful-rich-text", () => ({
  renderContentfulRichText: (doc: any, _: any, className: string) => (
    <div data-testid="rich-text" className={className}>
      Rich Text Content
    </div>
  ),
}));

jest.mock("@shared/utils/contentful/to-document", () => ({
  toDocument: (json: any) => json,
}));

describe("CartRetentionBanner", () => {
  const defaultFields: TypeCartRetentionBannerFields = {
    entryTitle: "Cart Banner",
    anchorId: "cart-banner",
    mainHeading: "Welcome back!",
    description: { json: { content: [{ nodeType: "paragraph" }] } },
    cta: { buttonLabel: "Continue checkout" },
  };

  beforeEach(() => {
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.useRealTimers();
  });

  describe("modal behavior", () => {
    it("renders a section with anchorId", () => {
      render(<CartRetentionBanner fields={defaultFields} />);
      const section = document.querySelector("section#cart-banner");
      expect(section).toBeInTheDocument();
    });

    it("renders with data-testid cart-retention-banner", () => {
      render(<CartRetentionBanner fields={defaultFields} />);
      expect(screen.getByTestId("cart-retention-banner")).toBeInTheDocument();
    });

    it("opens modal when checkShouldShowBanner returns true", async () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      // Allow useEffect to fire
      act(() => {
        jest.advanceTimersByTime(200);
      });

      const modal = screen.getByTestId("modal");
      expect(modal).toHaveAttribute("data-open", "true");
    });

    it("does not open modal when checkShouldShowBanner returns false", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(false);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      const modal = screen.getByTestId("modal");
      expect(modal).toHaveAttribute("data-open", "false");
    });

    it("calls onBannerShown when modal opens", () => {
      const onBannerShown = jest.fn();
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
          onBannerShown={onBannerShown}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(onBannerShown).toHaveBeenCalled();
    });

    it("closes modal and calls onClose", () => {
      const onClose = jest.fn();
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
          onClose={onClose}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      fireEvent.click(screen.getByTestId("modal-close"));
      expect(onClose).toHaveBeenCalled();
    });

    it("calls onContinueCheckout when CTA button is clicked in modal", () => {
      const onContinueCheckout = jest.fn();
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
          onContinueCheckout={onContinueCheckout}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      fireEvent.click(screen.getByTestId("banner-button"));
      expect(onContinueCheckout).toHaveBeenCalled();
    });

    it("uses default heading when mainHeading is not provided", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      const fields = { ...defaultFields, mainHeading: undefined };
      render(
        <CartRetentionBanner
          fields={fields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.getByText(/Welcome back/i)).toBeInTheDocument();
    });

    it("uses default CTA label when cta.buttonLabel is not provided", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      const fields = { ...defaultFields, cta: {} };
      render(
        <CartRetentionBanner
          fields={fields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.getByTestId("banner-button")).toHaveTextContent(
        "Continue checkout"
      );
    });

    it("renders rich text description in modal", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.getByTestId("rich-text")).toBeInTheDocument();
    });

    it("does not render rich text when description is undefined", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      const fields = { ...defaultFields, description: undefined };
      render(
        <CartRetentionBanner
          fields={fields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
    });

    it("passes type=cart-retention-banner to Modal", () => {
      render(<CartRetentionBanner fields={defaultFields} />);
      const modal = screen.getByTestId("modal");
      expect(modal).toHaveAttribute("data-type", "cart-retention-banner");
    });
  });

  describe("popup container mode", () => {
    it("renders inline content when isInPopupContainer is true", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      // Should render the pop-up-body div directly
      const popupBody = document.querySelector(".pop-up-body");
      expect(popupBody).toBeInTheDocument();
    });

    it("renders data-section-type attribute in popup mode", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      const div = document.querySelector(
        '[data-section-type="cart-retention-banner"]'
      );
      expect(div).toBeInTheDocument();
    });

    it("renders heading in popup mode", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      expect(screen.getByText("Welcome back!")).toBeInTheDocument();
    });

    it("renders default heading in popup mode when mainHeading is undefined", () => {
      const fields = { ...defaultFields, mainHeading: undefined };
      render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
      expect(screen.getByText(/Welcome back/)).toBeInTheDocument();
    });

    it("renders CTA in popup mode", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      expect(screen.getByTestId("banner-button")).toHaveTextContent(
        "Continue checkout"
      );
    });

    it("calls onContinueCheckout in popup mode", () => {
      const onContinueCheckout = jest.fn();
      render(
        <CartRetentionBanner
          fields={defaultFields}
          isInPopupContainer={true}
          onContinueCheckout={onContinueCheckout}
        />
      );
      fireEvent.click(screen.getByTestId("banner-button"));
      expect(onContinueCheckout).toHaveBeenCalled();
    });

    it("does not render Modal in popup mode", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      expect(screen.queryByTestId("modal")).not.toBeInTheDocument();
    });

    it("renders rich text in popup mode", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      expect(screen.getByTestId("rich-text")).toBeInTheDocument();
    });
  });

  describe("timer cleanup", () => {
    it("cleans up timeout on unmount", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(false);
      const { unmount } = render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );
      unmount();
      // No error should occur after unmount
      act(() => {
        jest.advanceTimersByTime(200);
      });
    });
  });

  describe("optional callback branches", () => {
    it("handles close without onClose callback", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      // Should not throw when clicking close without onClose
      fireEvent.click(screen.getByTestId("modal-close"));
      expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
    });

    it("handles continue checkout without onContinueCheckout callback", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      // Should not throw when clicking CTA without onContinueCheckout
      fireEvent.click(screen.getByTestId("banner-button"));
      expect(screen.getByTestId("banner-button")).toBeInTheDocument();
    });

    it("handles continue checkout in popup mode without callback", () => {
      render(
        <CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
      );
      // Should not throw
      fireEvent.click(screen.getByTestId("banner-button"));
      expect(screen.getByTestId("banner-button")).toBeInTheDocument();
    });

    it("opens modal without onBannerShown callback", () => {
      const checkShouldShowBanner = jest.fn().mockReturnValue(true);
      render(
        <CartRetentionBanner
          fields={defaultFields}
          checkShouldShowBanner={checkShouldShowBanner}
        />
      );

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "true");
    });

    it("does not open if checkShouldShowBanner is not provided", () => {
      render(<CartRetentionBanner fields={defaultFields} />);

      act(() => {
        jest.advanceTimersByTime(200);
      });

      expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
    });

    it("renders popup without description", () => {
      const fields = { ...defaultFields, description: undefined };
      render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
      expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
    });
  });
});
