import React, { useCallback, useEffect, useRef, useState } from "react";
import {
  CarouselWithProductCards,
  CarouselWithTestimonialCards,
  TabSwitchProps,
} from "./types";

import { Button } from "@shared/components/button";
import { MaterialIcon } from "@shared/components/material-icon";
import { ProductCard } from "@shared/contentful/blocks/cards/product-card";
import { TestimonialCard } from "@shared/contentful/blocks/cards/testimonial-card";
import { useCarouselSwipe } from "@shared/hooks/use-carousel-swipe";
import { CheckPlansProps } from "@shared/types/micro-components";
import { cx } from "@shared/utils";

function ProductCardPanel({
  fields,
  renderCheckPlans,
  isVisible = true,
}: {
  fields: CarouselWithProductCards;
  onModalButtonClick?: (id?: string) => void;
  renderCheckPlans?: (overrides?: CheckPlansProps) => React.ReactNode;
  isVisible?: boolean;
}) {
  const itemsExpanded = fields?.items?.items?.[0]?.benefitsExpanded || false;
  const [desktopExpanded, setDesktopExpanded] = useState(itemsExpanded);
  const [mobileExpandedStates, setMobileExpandedStates] = useState<
    Record<number, boolean>
  >({});
  const [currentIndex, setCurrentIndex] = useState(0);
  const [maxIndex, setMaxIndex] = useState(0);
  const [swipeOffset, setSwipeOffset] = useState(0);
  const [isSwiping, setIsSwiping] = useState(false);
  const items = fields?.items?.items || [];
  const isCarousel = items.length > 2;
  const showArrows = fields?.showArrows !== false && isCarousel;
  const cardsRef = useRef<(HTMLDivElement | null)[]>([]);
  const windowRef = useRef<HTMLDivElement | null>(null);
  const touchStartX = useRef<number>(0);

  // Determine how many cards fit so we never scroll past the last card
  useEffect(() => {
    if (!isCarousel || !isVisible) return;

    const gap = 16; // track gap-4 (16px)
    const cardWidth = 392 + gap; // card width + gap
    const trackMargin = 32; // inner track ml-8 (32px)
    const computeMaxIndex = () => {
      const containerWidth = windowRef.current?.offsetWidth || 0;
      // Skip while hidden (offsetWidth is 0) to avoid overestimating maxIndex
      if (containerWidth === 0) return;
      const usableWidth = containerWidth - trackMargin;
      const visibleCards = Math.max(
        1,
        Math.floor((usableWidth + gap) / cardWidth)
      );
      setMaxIndex(Math.max(0, items.length - visibleCards));
    };

    computeMaxIndex();
    window.addEventListener("resize", computeMaxIndex);
    return () => window.removeEventListener("resize", computeMaxIndex);
  }, [isCarousel, isVisible, items.length]);

  // Keep the active index within the available range
  useEffect(() => {
    setCurrentIndex(prev => Math.min(prev, maxIndex));
  }, [maxIndex]);

  const prevSlide = useCallback(() => {
    if (!isCarousel) return;
    setCurrentIndex(prev => Math.max(0, prev - 1));
  }, [isCarousel]);

  const nextSlide = useCallback(() => {
    if (!isCarousel) return;
    setCurrentIndex(prev => Math.min(maxIndex, prev + 1));
  }, [isCarousel, maxIndex]);

  // Touch/swipe handlers for finger-following drag (touch devices)
  const handleTouchStart = useCallback(
    (e: React.TouchEvent) => {
      if (!isCarousel) return;
      touchStartX.current = e.touches[0].clientX;
      setIsSwiping(true);
    },
    [isCarousel]
  );

  const handleTouchMove = useCallback(
    (e: React.TouchEvent) => {
      if (!isSwiping) return;
      const diff = e.touches[0].clientX - touchStartX.current;
      // Apply resistance when dragging past the start/end boundaries
      const atStart = currentIndex === 0;
      const atEnd = currentIndex >= maxIndex;
      if ((atStart && diff > 0) || (atEnd && diff < 0)) {
        setSwipeOffset(diff * 0.3);
      } else {
        setSwipeOffset(diff);
      }
    },
    [isSwiping, currentIndex, maxIndex]
  );

  const handleTouchEnd = useCallback(() => {
    if (!isSwiping) return;
    setIsSwiping(false);

    const containerWidth = windowRef.current?.offsetWidth || 0;
    const threshold = containerWidth * 0.15;

    if (swipeOffset > threshold) {
      prevSlide();
    } else if (swipeOffset < -threshold) {
      nextSlide();
    }

    setSwipeOffset(0);
  }, [isSwiping, swipeOffset, prevSlide, nextSlide]);

  // Equalize card heights
  useEffect(() => {
    if (!isCarousel || !isVisible) return;

    const equalizeHeights = () => {
      const cards = cardsRef.current.filter(Boolean) as HTMLDivElement[];
      if (cards.length === 0) return;

      // Reset heights first
      cards.forEach(card => {
        card.style.height = "auto";
      });

      // Find the tallest card
      const maxHeight = Math.max(...cards.map(card => card.offsetHeight));

      // Set all cards to the max height
      cards.forEach(card => {
        card.style.height = `${maxHeight}px`;
      });
    };

    // Run on mount and when expanded state changes
    equalizeHeights();

    // Re-run after a short delay due to dynamic content
    const timeoutId = setTimeout(equalizeHeights, 100);

    return () => clearTimeout(timeoutId);
  }, [isCarousel, isVisible, desktopExpanded, items.length]);

  if (!items.length && !fields?.title) {
    return null;
  }

  const renderCard = (
    item: any,
    globalIndex: number,
    isMobileView: boolean = false
  ) => {
    const planContent = item?.speed?.split("|");
    const planName = planContent?.[0] || "";
    const planSubtext = planContent?.[1] || "";
    const priceCents = item?.priceSuffix?.split("/")?.[0] || "00";
    const formattedPrice = `${item?.price || "0"}.${priceCents}`;
    const features = item?.benefits?.items || [];
    const bestValue = item?.highlighted || false;
    const rawBadge = item?.giftRewards?.list?.items || [];
    const innerBadge = {
      badgeText: item.innerBadge || "",
      badgeIcon: item.innerBadgeIcon?.url || "",
    };

    // Mobile: individual card state, Desktop: shared state
    const isExpanded = isMobileView
      ? mobileExpandedStates[globalIndex] || false
      : desktopExpanded;

    const handleToggle = () => {
      if (isMobileView) {
        setMobileExpandedStates(prev => ({
          ...prev,
          [globalIndex]: !prev[globalIndex],
        }));
      } else {
        setDesktopExpanded(!desktopExpanded);
      }
    };

    const handleCtaClick = () => {
      return;
    };

    return (
      <div
        ref={
          !isMobileView
            ? el => {
                if (el && !cardsRef.current.includes(el)) {
                  cardsRef.current[globalIndex] = el;
                }
              }
            : undefined
        }
        key={globalIndex}
        className={cx(
          isMobileView
            ? "mx-auto w-full max-w-[392px]"
            : "w-[392px] flex-shrink-0"
        )}
      >
        <ProductCard
          planName={planName}
          planSubtext={planSubtext}
          speed={item?.speed || ""}
          techType={item?.techType || ""}
          ismaxSpeed={item?.ismaxSpeed || ""}
          price={formattedPrice}
          description={item?.productCardDescription || ""}
          giftBadge={rawBadge}
          innerBadge={innerBadge}
          theme={item?.highlighted ? "dark" : "light"}
          bestValue={bestValue}
          bestValueText={item?.topBadgeText || "best value"}
          featuresTitle={item?.benefitsTitle}
          features={features}
          isExpanded={isExpanded}
          onToggleExpand={handleToggle}
          ctaText={item?.cta?.buttonLabel || "Select plan"}
          onCtaClick={handleCtaClick}
          renderCheckPlans={renderCheckPlans}
          cta={item.cta}
          hostType="smb"
        />
      </div>
    );
  };

  return !isCarousel ? (
    <div className="flex w-full max-w-[1280px] flex-wrap justify-center gap-4">
      {items.map((item, index) => renderCard(item, index))}
    </div>
  ) : (
    <>
      {/* Mobile/Tablet View: Vertical Stack */}
      <div className="flex flex-col gap-6 md:hidden">
        {items.map((item, index) => renderCard(item, index, true))}
      </div>

      {/* Desktop View: Horizontal Carousel */}
      <div className="relative hidden w-full md:block">
        {/* Navigation Arrows */}
        {showArrows && (
          <div className="pointer-events-none absolute -left-16 -right-16 top-[50%] z-30 flex -translate-y-1/2 justify-between px-4 md:px-10">
            {currentIndex > 0 ? (
              <Button
                onClick={prevSlide}
                className="pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full border border-gray-100 bg-white p-2 text-text shadow-cardDrop transition-all hover:bg-gray-50"
                aria-label="Previous"
              >
                <MaterialIcon name="arrow_back" size={24} />
              </Button>
            ) : (
              <span className="h-12 w-12" aria-hidden="true" />
            )}

            {currentIndex < maxIndex ? (
              <Button
                onClick={nextSlide}
                className="pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full border border-gray-100 bg-white p-2 text-text shadow-cardDrop transition-all hover:bg-gray-50"
                aria-label="Next"
              >
                <MaterialIcon name="arrow_forward" size={24} />
              </Button>
            ) : (
              <span className="h-12 w-12" aria-hidden="true" />
            )}
          </div>
        )}

        {/* Carousel Window */}
        <div
          ref={windowRef}
          className="mx-auto max-w-[1280px] select-none overflow-hidden"
          onTouchStart={handleTouchStart}
          onTouchMove={handleTouchMove}
          onTouchEnd={handleTouchEnd}
          onTouchCancel={handleTouchEnd}
        >
          <div
            className={cx(
              "ml-8 flex items-stretch gap-4 pb-4",
              isSwiping
                ? "transition-none"
                : "transition-transform duration-500 ease-in-out"
            )}
            style={{
              transform: `translateX(calc(-${currentIndex} * (392px + 16px) + ${swipeOffset}px))`,
            }}
          >
            {items.map((item, index) => renderCard(item, index, false))}
          </div>
        </div>
      </div>
    </>
  );
}

export function ProductCardCarousel({
  fields,
  renderCheckPlans,
  activeTab,
  tabs,
}: {
  fields: CarouselWithProductCards;
  onModalButtonClick?: (id?: string) => void;
  renderCheckPlans?: (overrides?: CheckPlansProps) => React.ReactNode;
  activeTab?: string;
  tabs?: string[];
}) {
  const allItems = fields?.items?.items || [];

  if (tabs && tabs.length > 1 && activeTab) {
    return (
      <>
        {tabs.map(tab => {
          const tabItems = allItems.filter(item => {
            const category = item.productCategory || tabs[0];
            return category === tab;
          });
          const tabFields = {
            ...fields,
            items: { ...fields.items, items: tabItems },
          };
          return (
            <div
              key={tab}
              style={{ display: tab === activeTab ? "block" : "none" }}
              aria-hidden={tab !== activeTab}
            >
              <ProductCardPanel
                fields={tabFields as CarouselWithProductCards}
                renderCheckPlans={renderCheckPlans}
                isVisible={tab === activeTab}
              />
            </div>
          );
        })}
      </>
    );
  }

  return (
    <ProductCardPanel fields={fields} renderCheckPlans={renderCheckPlans} />
  );
}

/**
 * Individual slide component for the testimonial carousel
 * Memoized to prevent unnecessary re-renders of inactive slides
 */
const TestimonialCarouselSlide = React.memo<{
  item: any;
  index: number;
  currentIndex: number;
  totalItems: number;
  swipeOffset: number;
  isSwiping: boolean;
  isMobile: boolean;
  containerWidth: number;
  cardOffsetPercentage: number;
}>(
  ({
    item,
    index,
    currentIndex,
    totalItems,
    swipeOffset,
    isSwiping,
    isMobile,
    containerWidth,
    cardOffsetPercentage,
  }) => {
    // Calculate circular offset for infinite carousel feel
    let offset = index - currentIndex;
    const len = totalItems;
    if (offset > len / 2) offset -= len;
    if (offset < -len / 2) offset += len;

    const isActive = offset === 0;
    const isAdjacent = Math.abs(offset) === 1;

    // Calculate card position with smooth swipe following
    // Base position is determined by card index offset (105% spacing between cards)
    const baseTransform = offset * cardOffsetPercentage;
    // Convert swipe pixels to percentage for smooth finger-following during swipe
    const swipePercentage = (swipeOffset / containerWidth) * 100;
    const totalTransform = baseTransform + swipePercentage;

    // Mobile: Show adjacent cards during swipe for preview effect
    // Desktop: Cards always visible (handled by opacity check below)
    const showOnMobile = isSwiping ? isActive || isAdjacent : isActive;

    // Determine opacity visibility (mobile-specific behavior)
    const isVisible = isMobile ? showOnMobile : true;

    return (
      <div
        className={cx(
          // Layout
          "col-start-1 row-start-1 w-full md:max-w-[815px]",
          // Performance: Hint browser to optimize transform and opacity animations
          "will-change-[transform,opacity]",
          // Z-index: Active slide on top
          isActive ? "z-10" : "z-5",
          // Visibility: Hide slides that are too far away (performance optimization)
          Math.abs(offset) > 1 ? "invisible" : "visible",
          // Opacity: Mobile fade effect for adjacent cards, desktop always visible
          isVisible ? "opacity-100" : "opacity-0",
          // Transitions: Faster during swipe, slower when snapping to position
          isSwiping
            ? "transition-opacity duration-200"
            : "transition-[transform,opacity] duration-500 ease-[cubic-bezier(0.25,0.46,0.45,0.94)]"
        )}
        style={{
          // Use CSS variable for dynamic transform value (can't be done with Tailwind)
          transform: `translateX(${totalTransform}%)`,
        }}
      >
        <TestimonialCard {...item} isActive={isActive} className="h-full" />
      </div>
    );
  }
);

TestimonialCarouselSlide.displayName = "TestimonialCarouselSlide";

export const TestimonialCarousel: React.FC<{
  fields: CarouselWithTestimonialCards;
  autoScroll?: boolean;
  autoScrollInterval?: number;
}> = ({ fields, autoScroll = true, autoScrollInterval = 8000 }) => {
  const testimonials = fields?.items?.items || [];

  if (!testimonials || testimonials.length === 0) {
    return null;
  }

  // Use the generic carousel swipe hook
  const carousel = useCarouselSwipe({
    itemCount: testimonials.length,
    cardOffsetPercentage: 105, // How far each card is offset (100% width + 5% gap)
    swipeThreshold: 0.15, //  Need to swipe 15% of screen to change slide
    mobileBreakpoint: 768, // Tailwind's md breakpoint, Mobile if width < 768px
    autoScrollInterval: autoScrollInterval, // 8 seconds between slides transition
    enableAutoScroll: autoScroll,
  });

  return (
    <div>
      <div className="relative max-w-[1280px] md:px-11">
        {/* Navigation Overlay - Left (Hidden on mobile) */}
        <Button
          onClick={carousel.prevSlide}
          className="group absolute left-5 top-1/2 z-50 hidden h-13 w-13 -translate-y-1/2 items-center justify-center rounded-full bg-white p-2 text-text shadow-md transition-colors hover:bg-gray-100 md:flex"
          aria-label="Previous"
        >
          <MaterialIcon name="arrow_back" size={24} />
        </Button>

        {/* Navigation Overlay - Right (Hidden on mobile) */}
        <Button
          onClick={carousel.nextSlide}
          className="group absolute right-5 top-1/2 z-50 hidden h-13 w-13 -translate-y-1/2 items-center justify-center rounded-full bg-white p-2 text-text shadow-md transition-colors hover:bg-gray-100 md:flex"
          aria-label="Next"
        >
          <MaterialIcon name="arrow_forward" size={24} />
        </Button>

        {/* Slider Track Wrapper */}
        <div
          ref={carousel.containerRef}
          className="select-none overflow-hidden rounded-card-sm will-change-transform"
          onTouchStart={carousel.handleTouchStart}
          onTouchMove={carousel.handleTouchMove}
          onTouchEnd={carousel.handleTouchEnd}
        >
          <div className="grid grid-cols-1 justify-items-center">
            {/* Slides */}
            {testimonials.map((item, index) => (
              <TestimonialCarouselSlide
                key={index}
                item={item}
                index={index}
                currentIndex={carousel.currentIndex}
                totalItems={testimonials.length}
                swipeOffset={carousel.swipeOffset}
                isSwiping={carousel.isSwiping}
                isMobile={carousel.isMobile}
                containerWidth={carousel.containerWidth}
                cardOffsetPercentage={carousel.constants.CARD_OFFSET_PERCENTAGE}
              />
            ))}
          </div>
        </div>
      </div>
      {/* Dots (Hidden on mobile) */}
      <div className="mt-5 flex justify-center gap-2 md:mt-10">
        {testimonials.map((_, idx) => (
          <button
            key={idx}
            onClick={() => carousel.goToSlide(idx)}
            className={cx(
              "h-2 w-2 rounded-full transition-all duration-300",
              carousel.currentIndex === idx
                ? "w-6 bg-white"
                : "bg-bg-fill-inverse-disabled hover:bg-white/60"
            )}
            aria-label={`Go to slide ${idx + 1}`}
          />
        ))}
      </div>
    </div>
  );
};

export const TabSwitch: React.FC<TabSwitchProps> = ({
  tabs,
  activeTab,
  onChange,
  className,
}) => {
  const activeIndex = tabs.indexOf(activeTab);
  const buttonRefs = useRef<(HTMLButtonElement | null)[]>([]);
  const [indicatorStyle, setIndicatorStyle] = useState({ width: 0, left: 0 });

  useEffect(() => {
    const activeButton = buttonRefs.current[activeIndex];
    if (activeButton) {
      setIndicatorStyle({
        width: activeButton.offsetWidth,
        left: activeButton.offsetLeft,
      });
    }
  }, [activeIndex, tabs]);

  return (
    <div className="flex w-full justify-center">
      <div
        className={cx(
          "relative flex w-fit gap-1 rounded-button-lg bg-bg-surface-active p-1 transition-all duration-200 ease-out",
          className
        )}
      >
        {/* Sliding background indicator */}
        <div
          className="absolute bottom-1 top-1 rounded-button bg-bg-fill-brand shadow-md transition-all duration-300 ease-out"
          style={{
            width: `${indicatorStyle.width}px`,
            left: `${indicatorStyle.left}px`,
          }}
        />

        {tabs.map((tab, index) => (
          <button
            key={tab}
            ref={el => {
              buttonRefs.current[index] = el;
            }}
            onClick={() => onChange(tab)}
            className={cx(
              "label1 relative z-10 flex min-w-[160px] items-center justify-center whitespace-nowrap rounded-button px-4 py-2.5 transition-colors duration-200 focus:outline-none active:bg-transparent",
              activeTab === tab
                ? "text-text-inverse"
                : "text-text-disabled hover:bg-bg-surface-hover"
            )}
          >
            {tab}
          </button>
        ))}
      </div>
    </div>
  );
};
