'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { useTranslations } from 'next-intl';

import { ChevronLeft, ChevronRight } from 'lucide-react';

import Section from '@/components/common/Section';
import CreationCarousel, {
  mapCreationsToCarouselItems,
} from '@/components/creations/CreationCarousel';
import SectionHeader from '@/components/home/components/SectionHeader';
import CarouselControls from '@/components/swiper/CarouselControls';
import { useAppSwiper } from '@/components/swiper/useAppSwiper';
import { Text } from '@/components/ui/typography';
import { cn } from '@/lib/utils';

import type { CreationListItem, TargyszoItem } from '@/types/Creation';

/* ============================================================================
   CREATION RECOMMENDATIONS  —  the tabbed recommender at the foot of the work
   page. A shared title with tabs beneath it: an "others viewed this" tab driven
   by the creator-based recommendation pool, then one tab per subject tag. Each
   tab activation re-fetches through /api/creation-recommendations, which shuffles
   server-side — so flipping between tabs keeps surfacing fresh picks.
   ========================================================================== */

type Tab =
  | { key: 'recommended'; label: string; type: 'recommended' }
  | { key: string; label: string; type: 'tag'; tagId: number };

interface CreationRecommendationsProps {
  /** primary creator identifier — enables the recommended tab; null hides it. */
  creatorIdentifier: string | null;
  /** the creation being viewed — excluded from every tab so we never recommend it. */
  currentCreationId: string | null;
  tags: TargyszoItem[];
  /** SSR-resolved items for the initially active tab, to avoid an empty first paint. */
  initialCreations: CreationListItem[];
}

const buildQuery = (
  tab: Tab,
  creatorIdentifier: string | null,
  currentCreationId: string | null
) => {
  const params = new URLSearchParams();
  // drop the creation being viewed from whichever list this tab requests
  if (currentCreationId) params.set('excludeId', currentCreationId);
  if (tab.type === 'recommended') {
    params.set('type', 'recommended');
    if (creatorIdentifier) params.set('identifier', creatorIdentifier);
  } else {
    params.set('type', 'tag');
    params.set('tagId', String(tab.tagId));
  }
  return params.toString();
};

const SkeletonRow: React.FC = () => (
  <div className="flex gap-4 overflow-hidden" aria-hidden="true">
    {Array.from({ length: 5 }).map((_, index) => (
      <div
        key={index}
        className="h-[var(--creation-carousel-image-height,220px)] w-[280px] shrink-0 animate-pulse rounded-[2px] bg-brand-primary/[0.06]"
      />
    ))}
  </div>
);

const CreationRecommendations: React.FC<CreationRecommendationsProps> = ({
  creatorIdentifier,
  currentCreationId,
  tags,
  initialCreations,
}) => {
  const t = useTranslations('creationPage');
  const tCommon = useTranslations('common');

  const tabs = useMemo<Tab[]>(() => {
    const result: Tab[] = [];
    if (creatorIdentifier) {
      result.push({ key: 'recommended', label: t('related.recommendedTab'), type: 'recommended' });
    }
    // jelolt === false → keyword stays in the tag list but earns no recommender tab.
    for (const tag of tags) {
      if (tag.jelolt === false) continue;
      result.push({ key: `tag-${tag.id}`, label: tag.nev, type: 'tag', tagId: tag.id });
    }
    return result;
  }, [creatorIdentifier, tags, t]);

  const [activeKey, setActiveKey] = useState(() => tabs[0]?.key ?? '');
  const [items, setItems] = useState(() => {
    return mapCreationsToCarouselItems(initialCreations);
  });
  const [loading, setLoading] = useState(false);

  // own the swiper controller so the nav arrows can sit on the tab row instead
  // of forcing the carousel to open a separate controls row beneath the tabs.
  const controller = useAppSwiper({ slideCount: items.length, autoplay: false, loop: false });
  const hasTabBar = tabs.length > 1;

  // scrollable tab strip — desktop has no touch scroll, so overflowing tabs are
  // only reachable through the pager chevrons we show when there is overflow.
  const tabStripRef = useRef<HTMLDivElement>(null);
  const [canScrollLeft, setCanScrollLeft] = useState(false);
  const [canScrollRight, setCanScrollRight] = useState(false);

  const updateTabOverflow = useCallback(() => {
    const el = tabStripRef.current;
    if (!el) return;
    setCanScrollLeft(el.scrollLeft > 1);
    setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
  }, []);

  useEffect(() => {
    const el = tabStripRef.current;
    if (!el) return;
    updateTabOverflow();
    const observer = new ResizeObserver(updateTabOverflow);
    observer.observe(el);
    return () => observer.disconnect();
  }, [updateTabOverflow, tabs]);

  const pageTabs = (direction: 1 | -1) => {
    const el = tabStripRef.current;
    if (!el) return;
    el.scrollBy({ left: direction * el.clientWidth * 0.75, behavior: 'smooth' });
  };

  const selectTab = (key: string) => {
    setActiveKey(key);
    controller.goTo(0); // reset scroll position when switching tabs
  };

  // the first active tab is hydrated from SSR; only skip the fetch when we
  // actually received items for it, otherwise fetch on mount.
  const skipNextFetch = useRef(initialCreations.length > 0);

  useEffect(() => {
    const tab = tabs.find((candidate) => candidate.key === activeKey);
    if (!tab) return;

    if (skipNextFetch.current) {
      skipNextFetch.current = false;
      return;
    }

    let cancelled = false;
    setLoading(true);

    fetch(
      `/api/creation-recommendations?${buildQuery(tab, creatorIdentifier, currentCreationId)}`
    )
      .then((response) => response.json())
      .then((json) => {
        if (cancelled) return;
        const data = Array.isArray(json?.data) ? (json.data as CreationListItem[]) : [];
        setItems(mapCreationsToCarouselItems(data));
      })
      .catch(() => {
        if (!cancelled) setItems([]);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, [activeKey, tabs, creatorIdentifier, currentCreationId]);

  if (tabs.length === 0) return null;

  return (
    <Section surface="white">
      <div className="flex flex-col gap-6">
        {/* title row — the carousel nav arrows live here, kept clear of the tab
            strip below so they never read as tab-scroll controls */}
        <div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
          <SectionHeader eyebrow={t('related.similarEyebrow')} title={t('related.similarTitle')} />

          {items.length > 1 && (
            <CarouselControls
              total={items.length}
              activeIndex={controller.activeIndex}
              onPrev={controller.prev}
              onNext={controller.next}
              onSelect={controller.goTo}
              showDots={false}
              className="hidden shrink-0 sm:flex sm:justify-end"
            />
          )}
        </div>

        {/* tabs — single-row horizontal scroll on every breakpoint, paged by the
            edge chevrons that appear only when the strip overflows */}
        {hasTabBar && (
          <div className="relative border-b border-brand-primary/10">
            {canScrollLeft && (
              <button
                type="button"
                aria-label={tCommon('previous')}
                onClick={() => pageTabs(-1)}
                className="absolute inset-y-0 left-0 z-10 flex items-center bg-gradient-to-r from-brand-secondary from-60% to-transparent pb-2 pl-1 pr-6 text-brand-primary/60 transition-colors hover:text-brand-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mma-blue"
              >
                <ChevronLeft className="size-5" aria-hidden="true" />
              </button>
            )}

            <div
              ref={tabStripRef}
              role="tablist"
              aria-label={t('related.similarTitle')}
              onScroll={updateTabOverflow}
              className="-mb-px flex gap-x-6 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
            >
              {tabs.map((tab) => {
                const isActive = tab.key === activeKey;
                return (
                  <button
                    key={tab.key}
                    type="button"
                    role="tab"
                    aria-selected={isActive}
                    onClick={(event) => {
                      selectTab(tab.key);
                      event.currentTarget.scrollIntoView({
                        behavior: 'smooth',
                        block: 'nearest',
                        inline: 'nearest',
                      });
                    }}
                    className={cn(
                      'shrink-0 whitespace-nowrap border-b-2 pb-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mma-blue focus-visible:ring-offset-2',
                      isActive
                        ? 'border-mma-blue text-brand-primary'
                        : 'border-transparent text-brand-primary/45 hover:text-brand-primary'
                    )}
                  >
                    <Text as="span" variant="meta">
                      {tab.label}
                    </Text>
                  </button>
                );
              })}
            </div>

            {canScrollRight && (
              <button
                type="button"
                aria-label={tCommon('next')}
                onClick={() => pageTabs(1)}
                className="absolute inset-y-0 right-0 z-10 flex items-center bg-gradient-to-l from-brand-secondary from-60% to-transparent pb-2 pl-6 pr-1 text-brand-primary/60 transition-colors hover:text-brand-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mma-blue"
              >
                <ChevronRight className="size-5" aria-hidden="true" />
              </button>
            )}
          </div>
        )}

        <div className={cn('transition-opacity duration-200', loading && 'opacity-50')}>
          {items.length > 0 ? (
            <CreationCarousel
              key={activeKey}
              items={items}
              showScrollbar
              controller={controller}
              showControls={false}
            />
          ) : loading ? (
            <SkeletonRow />
          ) : (
            <Text tone="muted">{t('related.empty')}</Text>
          )}
        </div>
      </div>
    </Section>
  );
};

export default CreationRecommendations;
