// @design-system: domain/Lightbox

'use client';

import { useMemo, useRef, useState, type PointerEvent } from 'react';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogTitle,
} from '@/components/ui/overlays/Dialog';
import { Button } from '@/components/ui/primitives/Button';
import { IconButton } from '@/components/ui/primitives/IconButton';
import { Icon } from '@/components/ui/icons/Icon';
import { Image } from '@/components/ui/primitives/Image';
import { cn } from '@/lib/cn';
import { useT } from '@/lib/i18n/react';

const MIN_ZOOM = 1;
const MAX_ZOOM = 3;
const ZOOM_STEP = 0.5;
const SWIPE_THRESHOLD_PX = 48;

export interface LightboxImage {
  id: string;
  src: string;
  alt: string;
}

export interface LightboxProps {
  images: LightboxImage[];
  open: boolean;
  activeIndex: number;
  onOpenChange: (open: boolean) => void;
  onActiveIndexChange: (index: number) => void;
  className?: string;
}

function clampZoom(value: number): number {
  return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, value));
}

function clampIndex(index: number, total: number): number {
  if (total === 0) return 0;
  return ((index % total) + total) % total;
}

export function Lightbox({
  images,
  open,
  activeIndex,
  onOpenChange,
  onActiveIndexChange,
  className,
}: LightboxProps) {
  const t = useT('domain_gallery');
  const [zoom, setZoom] = useState(MIN_ZOOM);
  const swipeStartXRef = useRef<number | null>(null);

  const total = images.length;
  const safeIndex = useMemo(() => clampIndex(activeIndex, total), [activeIndex, total]);
  const activeImage = total > 0 ? images[safeIndex] : null;

  const canNavigate = total > 1;

  const goPrev = () => {
    if (!canNavigate) return;
    setZoom(MIN_ZOOM);
    onActiveIndexChange(clampIndex(safeIndex - 1, total));
  };

  const goNext = () => {
    if (!canNavigate) return;
    setZoom(MIN_ZOOM);
    onActiveIndexChange(clampIndex(safeIndex + 1, total));
  };

  const handleOpenChange = (nextOpen: boolean) => {
    setZoom(MIN_ZOOM);
    onOpenChange(nextOpen);
  };

  const handleZoomIn = () => setZoom((value) => clampZoom(value + ZOOM_STEP));
  const handleZoomOut = () => setZoom((value) => clampZoom(value - ZOOM_STEP));

  const handleSwipeStart = (event: PointerEvent<HTMLDivElement>) => {
    if (event.pointerType !== 'touch') return;
    swipeStartXRef.current = event.clientX;
  };

  const handleSwipeEnd = (event: PointerEvent<HTMLDivElement>) => {
    if (event.pointerType !== 'touch') return;
    const startX = swipeStartXRef.current;
    const endX = event.clientX;
    swipeStartXRef.current = null;
    if (startX == null || endX == null) return;
    const deltaX = endX - startX;
    if (Math.abs(deltaX) < SWIPE_THRESHOLD_PX) return;
    const isRtl = getComputedStyle(event.currentTarget).direction === 'rtl';
    const swipedTowardsNext = isRtl ? deltaX > 0 : deltaX < 0;
    if (swipedTowardsNext) {
      goNext();
      return;
    }
    goPrev();
  };

  if (!activeImage) return null;

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogContent
        data-testid={lightboxTestIds.dialog}
        aria-describedby="lightbox-description"
        className={cn(
          'bg-surface-overlay z-modal flex h-[100dvh] w-full max-w-none items-center justify-center border-0 p-0 shadow-none',
          'motion-reduce:animate-none motion-reduce:transition-none',
          className,
        )}
      >
        <DialogTitle className="sr-only">{t('lightbox_title')}</DialogTitle>
        <DialogDescription id="lightbox-description" className="sr-only">
          {t('lightbox_description')
            .replace('{{index}}', String(safeIndex + 1))
            .replace('{{total}}', String(total))}
        </DialogDescription>

        <div className="flex h-full w-full flex-col">
          <div className="flex items-center justify-between gap-3 px-4 pt-[calc(var(--spacing-6)+var(--safe-area-top))] pb-3 md:px-6">
            <p className="text-text-inverse text-sm font-medium">
              {t('lightbox_counter')
                .replace('{{index}}', String(safeIndex + 1))
                .replace('{{total}}', String(total))}
            </p>
            <div className="flex items-center gap-2">
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={handleZoomOut}
                aria-label={t('zoom_out')}
                disabled={zoom <= MIN_ZOOM}
              >
                <Icon name="Minus" size="sm" />
              </Button>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={handleZoomIn}
                aria-label={t('zoom_in')}
                disabled={zoom >= MAX_ZOOM}
              >
                <Icon name="Plus" size="sm" />
              </Button>
            </div>
          </div>

          <div
            data-testid="lightbox-gesture-area"
            className="relative flex min-h-0 flex-1 items-center justify-center overflow-hidden px-4 pb-4 md:px-6 md:pb-6"
            onPointerDown={handleSwipeStart}
            onPointerUp={handleSwipeEnd}
          >
            {canNavigate ? (
              <IconButton
                variant="overlay"
                size="xl"
                shape="circle"
                onClick={goPrev}
                aria-label={t('prev')}
                className="absolute start-4 top-1/2 z-10 -translate-y-1/2"
              >
                <Icon name="ChevronLeft" size="md" mirror />
              </IconButton>
            ) : null}

            <div className="flex h-full w-full items-center justify-center">
              <Image
                src={activeImage.src}
                alt={activeImage.alt}
                loading="eager"
                fetchpriority="high"
                data-testid={lightboxTestIds.image}
                className="max-h-full max-w-full object-contain transition-transform duration-[var(--duration-fast)] motion-reduce:transition-none"
                style={{ transform: `scale(${zoom})` }}
              />
            </div>

            {canNavigate ? (
              <IconButton
                variant="overlay"
                size="xl"
                shape="circle"
                onClick={goNext}
                aria-label={t('next')}
                className="absolute end-4 top-1/2 z-10 -translate-y-1/2"
              >
                <Icon name="ChevronRight" size="md" mirror />
              </IconButton>
            ) : null}
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

export const lightboxTestIds = {
  dialog: 'lightbox-dialog',
  image: 'lightbox-image',
} as const;
