// @design-system: domain/DealCard
'use client';

import React, { useEffect, useRef, useState } from 'react';
import { formatCountdownSeconds, getCountdownStage, type CountdownStage } from '@/lib/countdown';
import { useCountdown } from '@/lib/hooks/useCountdown';
import type { VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/cn';
import { Image } from '@/components/ui/primitives/Image';
import { Icon } from '@/components/ui/icons/Icon';
import { Button } from '@/components/ui/primitives/Button';
import { StarRating } from '@/components/ui/primitives/StarRating';
import { useT, useLocale } from '@/lib/i18n/react';
import { interpolate } from '@/lib/i18n/interpolate';
import { formatRelative } from '@/lib/format';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/overlays/Tooltip/Tooltip';
import { formatAgorotPricePrefixed } from '@/lib/money';
import { dealCardVariants } from './variants';
import { DealCardCornerCta } from '@/components/ui/domain/DealCard/DealCardCornerCta';
import { useDealStock, type DealStockState } from '@/features/deals/useDealStock.js';

import type { DealType } from '@/lib/deal-types';
export type { DealType };

export interface DealCardDeal {
  id: string;
  title: string;
  vendorId?: string;
  vendorName: string;
  /** Optional vendor avatar URL — renders size-6 circle; shows initial fallback when absent. */
  vendorAvatarUrl?: string;
  city: string;
  originalPrice: number;
  discountedPrice: number;
  imageSrc: string;
  imageAlt: string;
  windowEnd: string | null;
  stockRemaining?: number;
  stockTotal?: number;
  dealType: DealType;
  discountPercent: number;
  isHotDeal?: boolean;
  soldCount?: number;
  /** Vendor address latitude — present when feed returns geo data (Near-You / radius mode). */
  lat?: number;
  /** Vendor address longitude — present when feed returns geo data (Near-You / radius mode). */
  lng?: number;
  // ── Variant-aware cache cols (Wave 9) ──────────────────────────────────────
  /** Minimum discounted price across all active SKUs (numeric string from DB). */
  minPrice?: string | null;
  /** Maximum discounted price across all active SKUs (numeric string from DB). */
  maxPrice?: string | null;
  /** Maximum discount percent across all active SKUs. */
  maxDiscountPercent?: number | null;
  /** Number of active variant axes. 0 = single-SKU deal (direct add-to-cart). */
  axesCount?: number;
  /** ID of the default/only SKU for single-variant deals; null when variants exist. */
  defaultSkuId?: string | null;
  /** Headline qty-tier for the grid badge: highest-discount tier across the deal's SKUs. Null if none. */
  qtyTierTop?: { minQty: number; discountPercent: number } | null;
  /** Number of SKUs on this deal (>=1). Lets the badge distinguish single- vs multi-SKU deals. */
  skuCount?: number;
  /** Hebrew slug for canonical deal URL — links to /deals/<heSlug> when present. */
  heSlug?: string;
}

export interface DealCardProps extends VariantProps<typeof dealCardVariants> {
  deal: DealCardDeal;
  className?: string;
  demo?: boolean;
  aboveFold?: boolean;
  /** Distance from user to deal location in km — renders badge when provided. */
  distanceKm?: number;
  /** Vendor rating — renders StarRating in body row 1 when provided. */
  rating?: { value: number; count: number };
  onAuthRequired?: () => void;
}

/** Props for the draft variant of DealCard. */
export interface DraftDealCardProps {
  id: string;
  title: string | null;
  updatedAt: Date | string;
  isStarred: boolean;
  onToggleStar: () => void;
  onResume: () => void;
  onDelete: () => void;
  className?: string;
}

/** Draft variant of DealCard — shown in the vendor draft list. */
function DraftDealCardInner({
  title,
  updatedAt,
  isStarred,
  onToggleStar,
  onResume,
  onDelete,
  className,
}: DraftDealCardProps) {
  const t = useT('vendorDrafts');
  const { locale } = useLocale();

  const displayTitle = title ?? t('untitled');
  const relativeTime = interpolate(t('updatedRelative'), {
    time: formatRelative(updatedAt, locale),
  });

  return (
    <TooltipProvider>
      <article
        data-testid="deal-card"
        className={cn(dealCardVariants({ variant: 'draft' }), 'gap-3 p-4', className)}
        aria-label={displayTitle}
      >
        <div className="flex items-start gap-2">
          <div className="flex min-w-0 flex-1 flex-col gap-1">
            <p className="h4 truncate">{displayTitle}</p>
            <p className="caption text-text-muted">{relativeTime}</p>
          </div>
          <Tooltip>
            <TooltipTrigger asChild>
              <button
                type="button"
                onClick={onToggleStar}
                aria-label={isStarred ? t('unstar') : t('starToggle')}
                aria-pressed={isStarred}
                className={cn(
                  'focus-visible:outline-brand-primary-500 shrink-0 rounded-md p-1.5 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2',
                  isStarred
                    ? 'text-warning-500 hover:text-warning-600'
                    : 'text-text-muted hover:text-text-default',
                )}
              >
                <Icon
                  name="Star"
                  size="sm"
                  className={isStarred ? 'fill-warning-400' : undefined}
                />
              </button>
            </TooltipTrigger>
            <TooltipContent>{t('starTooltip')}</TooltipContent>
          </Tooltip>
        </div>
        <div className="flex gap-2">
          <Button
            variant="primary"
            size="sm"
            className="flex-1"
            onClick={onResume}
            aria-label={t('resumeEditing')}
          >
            {t('resumeEditing')}
          </Button>
          <Tooltip>
            <TooltipTrigger asChild>
              <Button
                variant="ghost"
                size="sm"
                className="text-danger-600 hover:bg-danger-50 hover:text-danger-700"
                onClick={onDelete}
                aria-label={t('delete')}
              >
                {t('delete')}
              </Button>
            </TooltipTrigger>
            <TooltipContent>{t('deleteTooltip')}</TooltipContent>
          </Tooltip>
        </div>
      </article>
    </TooltipProvider>
  );
}

export const DraftDealCard = React.memo(DraftDealCardInner);

// Module-level: track prefetched deal IDs to avoid duplicate <link> elements.
const _prefetchedDeals = new Set<string>();

function _prefetchDeal(dealId: string, heSlug?: string): void {
  if (typeof document === 'undefined' || _prefetchedDeals.has(dealId)) return;
  _prefetchedDeals.add(dealId);
  const link = document.createElement('link');
  link.rel = 'prefetch';
  link.href = heSlug ? `/deals/${heSlug}` : '/deals';
  document.head.appendChild(link);
}

function SingleSkuStockRegion({
  stock,
  stockTotal,
}: {
  stock: DealStockState;
  stockTotal?: number;
}) {
  const t = useT('deal-card');
  const tCard = useT('domain_deal_card');
  const isPending = stock.status === 'loading' || stock.status === 'error';
  const stockPct =
    !isPending && stockTotal
      ? Math.max(0, Math.min(100, ((stockTotal - stock.stockRemaining) / stockTotal) * 100))
      : null;

  return (
    <div className="flex min-h-[1.375rem] flex-col gap-1" aria-live="polite" aria-busy={isPending}>
      {isPending ? (
        <span
          aria-label={t('loadingAvailability')}
          className="bg-surface-subtle text-text-secondary inline-block min-w-[4.5rem] rounded-full px-2 py-0.5 text-xs tabular-nums"
        >
          {t('loadingAvailability')}
        </span>
      ) : (
        <>
          <span className="text-text-muted text-xs tabular-nums">
            {tCard('remaining')} {stock.stockRemaining}
          </span>
          {stockPct !== null && (
            <div
              role="progressbar"
              aria-valuenow={Math.round(stockPct)}
              aria-valuemin={0}
              aria-valuemax={100}
              aria-label={t('stock_progress')}
              className="bg-surface-subtle h-1.5 overflow-hidden rounded-full"
            >
              <div
                className="bg-brand-primary-500 h-full rounded-full"
                style={{ width: `${stockPct}%` }}
              />
            </div>
          )}
        </>
      )}
    </div>
  );
}

function getDealHeroViewTransitionName(dealId: string): string {
  return `deal-hero-${dealId}`;
}

function usePrefersReducedMotion(): boolean {
  const [prefersReducedMotion, setPrefersReducedMotion] = useState(true);

  useEffect(() => {
    if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
    const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
    const sync = () => {
      setPrefersReducedMotion(mediaQuery.matches);
    };
    sync();
    mediaQuery.addEventListener('change', sync);
    return () => {
      mediaQuery.removeEventListener('change', sync);
    };
  }, []);

  return prefersReducedMotion;
}

function useDocumentDirection(): 'ltr' | 'rtl' {
  const [direction, setDirection] = useState<'ltr' | 'rtl'>('ltr');

  useEffect(() => {
    if (typeof document === 'undefined') return;
    const sync = () => {
      setDirection(document.documentElement.dir === 'rtl' ? 'rtl' : 'ltr');
    };
    sync();
    const observer = new MutationObserver(sync);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['dir'],
    });
    return () => {
      observer.disconnect();
    };
  }, []);

  return direction;
}

function DiscountBadge({ label, savePct }: { label: string; savePct: number }) {
  const badgeRef = useRef<HTMLSpanElement>(null);
  const prefersReducedMotion = usePrefersReducedMotion();
  const direction = useDocumentDirection();
  const hasPlayedRef = useRef(false);

  useEffect(() => {
    const badge = badgeRef.current;
    if (!badge || prefersReducedMotion || hasPlayedRef.current) return;

    const play = () => {
      if (!badgeRef.current || hasPlayedRef.current) return;
      hasPlayedRef.current = true;
      const styles = getComputedStyle(badgeRef.current);
      const frames =
        direction === 'rtl'
          ? [
              { backgroundPosition: styles.getPropertyValue('--deal-card-foil-start-rtl') },
              { backgroundPosition: styles.getPropertyValue('--deal-card-foil-end-rtl') },
            ]
          : [
              { backgroundPosition: styles.getPropertyValue('--deal-card-foil-start-ltr') },
              { backgroundPosition: styles.getPropertyValue('--deal-card-foil-end-ltr') },
            ];
      const animation = badgeRef.current.animate(frames, {
        duration: Number.parseFloat(styles.getPropertyValue('--deal-card-foil-duration-ms')),
        easing: styles.getPropertyValue('--deal-card-foil-easing'),
        fill: 'none',
      });
      animation.addEventListener(
        'finish',
        () => {
          animation.cancel();
        },
        { once: true },
      );
    };

    if (typeof IntersectionObserver === 'undefined') {
      play();
      return;
    }

    const observer = new IntersectionObserver(
      (entries) => {
        if (!entries.some((entry) => entry.isIntersecting)) return;
        observer.disconnect();
        play();
      },
      { threshold: 0.35 },
    );

    observer.observe(badge);
    return () => {
      observer.disconnect();
    };
  }, [direction, prefersReducedMotion]);

  return (
    <span
      ref={badgeRef}
      dir="ltr"
      data-testid="deal-card-discount-badge"
      data-foil-direction={direction}
      aria-label={label}
      className="text-neutral-0 tracking-price-tight absolute end-2.5 top-2.5 rounded-md px-2 py-1 font-[family-name:var(--font-en)] text-xs font-[var(--font-weight-extrabold)] tabular-nums"
      style={{
        backgroundColor: 'var(--deal-card-foil-background)',
        backgroundImage: 'var(--deal-card-foil-gradient)',
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'var(--deal-card-foil-size)',
        backgroundPosition:
          direction === 'rtl'
            ? 'var(--deal-card-foil-start-rtl)'
            : 'var(--deal-card-foil-start-ltr)',
      }}
    >
      −{savePct}%
    </span>
  );
}

function DealCardContent({
  deal,
  variant,
  className,
  aboveFold,
  distanceKm,
  rating,
  onAuthRequired,
  singleSkuStock,
}: DealCardProps & { singleSkuStock: DealStockState | null }) {
  const t = useT('deal-card');
  const displayTitle = (deal.title ?? '').trim() || t('untitledDeal');
  const tCard = useT('domain_deal_card');
  const tVariants = useT('variants');
  const tTime = useT('time');
  const { locale } = useLocale();
  const containerRef = useRef<HTMLAnchorElement>(null);
  const prefersReducedMotion = usePrefersReducedMotion();
  const secondsLeft = useCountdown(deal.windowEnd, containerRef);
  const stage: CountdownStage = getCountdownStage(secondsLeft ?? 0);
  const timeLabels = {
    days: tTime('days'),
    hours: tTime('hours'),
    minutes: tTime('minutes'),
    seconds: tTime('seconds'),
  };
  const countdown = secondsLeft != null ? formatCountdownSeconds(secondsLeft, timeLabels) : null;
  const isExpired = secondsLeft !== null && secondsLeft <= 0;

  // Prefer cache cols; fall back to legacy scalar fields
  const effectiveMinPrice = deal.minPrice != null ? Number(deal.minPrice) : deal.discountedPrice;
  const effectiveMaxPrice = deal.maxPrice != null ? Number(deal.maxPrice) : deal.discountedPrice;
  const savePct = deal.maxDiscountPercent ?? deal.discountPercent;
  // deals cache cols hold the discounted-price range only; derive the strikethrough
  // pre-discount price from the sale price + percent rather than deal.originalPrice
  // (which now mirrors max_price = the discounted figure for single-SKU deals).
  const strikethroughPrice =
    savePct > 0 && savePct < 100 ? effectiveMinPrice / (1 - savePct / 100) : deal.originalPrice;
  const showRange = effectiveMinPrice !== effectiveMaxPrice;
  const hasAxes = (deal.axesCount ?? 0) > 0;
  const heroViewTransitionName = prefersReducedMotion
    ? 'none'
    : deal.heSlug
      ? getDealHeroViewTransitionName(deal.id)
      : 'none';

  const isRow = variant === 'feed-row';
  const isScrollCard = variant === 'scroll';

  const handlePrefetch = () => _prefetchDeal(deal.id, deal.heSlug);

  return (
    <a
      ref={containerRef}
      href={deal.heSlug ? `/deals/${deal.heSlug}` : '/deals'}
      data-testid="deal-card"
      data-deal-card
      data-deal-card-scroll={isScrollCard ? 'true' : undefined}
      data-deal-id={deal.id}
      onMouseEnter={handlePrefetch}
      onFocus={handlePrefetch}
      className={cn(dealCardVariants({ variant }), 'no-underline', className)}
      aria-label={displayTitle}
    >
      {/* ── Media ── */}
      <div
        data-shared-transition="deal-card-hero"
        className={cn(
          'bg-brand-primary-50 group relative overflow-hidden',
          isRow ? 'aspect-square w-[40%] shrink-0' : 'aspect-[4/3] w-full',
        )}
        style={{ viewTransitionName: heroViewTransitionName }}
      >
        <Image
          src={deal.imageSrc}
          alt={deal.imageAlt || displayTitle}
          width={isRow ? 200 : 320}
          height={isRow ? 200 : 240}
          loading={aboveFold ? 'eager' : 'lazy'}
          fetchpriority={aboveFold ? 'high' : undefined}
          sizes="(max-width: 40rem) 100vw, 20rem"
          className="h-full w-full object-cover"
        />

        {/* Discount badge — top-end, dark bg, white text */}
        <DiscountBadge
          label={t('discount_aria').replace('{savePct}', String(savePct))}
          savePct={savePct}
        />

        <DealCardCornerCta
          dealId={deal.id}
          defaultSkuId={deal.defaultSkuId ?? null}
          hasAxes={hasAxes}
          isSoldOut={false}
          variant={variant ?? undefined}
          title={displayTitle}
          imageUrl={deal.imageSrc}
          onAuthRequired={onAuthRequired}
          dealType={deal.dealType}
          heSlug={deal.heSlug}
        />

        {/* Distance badge — bottom-end, only if distanceKm present */}
        {distanceKm != null && (
          <span className="bg-surface-default/90 text-text-default absolute end-2 bottom-2 rounded-full px-2 py-0.5 text-xs font-semibold backdrop-blur">
            {tCard('distance_km').replace('{{dist}}', String(distanceKm))}
          </span>
        )}
      </div>

      {/* ── Body ── */}
      <div className={cn('flex flex-1 flex-col gap-2.5', 'p-3')}>
        {/* Row 1: vendor avatar + name + rating */}
        <div className="flex min-w-0 items-center gap-1.5">
          {/* Vendor avatar */}
          {deal.vendorAvatarUrl ? (
            <Image
              src={deal.vendorAvatarUrl}
              alt=""
              decorative
              width={24}
              height={24}
              loading="lazy"
              className="h-6 w-6 shrink-0 rounded-full object-cover"
            />
          ) : (
            <span
              aria-hidden
              className="bg-surface-subtle text-text-muted inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold"
            >
              {deal.vendorName.charAt(0)}
            </span>
          )}
          {/* Vendor name */}
          <span className="text-text-default min-w-0 truncate text-sm font-semibold">
            {deal.vendorName}
          </span>
          {/* Rating */}
          {rating && (
            <StarRating
              value={rating.value}
              count={rating.count}
              size="sm"
              className="ms-auto shrink-0"
            />
          )}
        </div>

        {/* Row 2: Title */}
        <div className="text-text-primary line-clamp-2 text-base leading-tight font-extrabold">
          {displayTitle}
        </div>

        {/* Footer: price + stock bar + CTA + timer anchored to bottom together */}
        <div className="mt-auto flex flex-col gap-1.5 pt-1.5">
          {/* Price row */}
          <div className="flex items-baseline gap-2">
            {showRange ? (
              <span className="text-brand-primary-800 tracking-price-tight font-[family-name:var(--font-en)] text-base font-extrabold tabular-nums">
                {tVariants('price_from').replace(
                  '{price}',
                  formatAgorotPricePrefixed(Math.round(effectiveMinPrice * 100)),
                )}
              </span>
            ) : (
              <>
                <span className="text-brand-primary-800 tracking-price-tight font-[family-name:var(--font-en)] text-2xl font-extrabold tabular-nums">
                  {formatAgorotPricePrefixed(Math.round(effectiveMinPrice * 100))}
                </span>
                <span className="text-text-muted font-[family-name:var(--font-en)] text-sm tabular-nums line-through">
                  {formatAgorotPricePrefixed(Math.round(strikethroughPrice * 100))}
                </span>
              </>
            )}
          </div>
          {/* Qty-tier badge — rendered only when a headline tier exists */}
          {deal.qtyTierTop && (
            <span className="text-brand-primary-700 bg-brand-primary-50 mt-1 inline-block rounded px-2 py-0.5 text-xs font-bold">
              {((deal.skuCount ?? 1) > 1
                ? tVariants('qty_tier_badge_multi')
                : tVariants('qty_tier_badge')
              )
                .replace('{minQty}', String(deal.qtyTierTop.minQty))
                .replace('{percent}', String(deal.qtyTierTop.discountPercent))}
            </span>
          )}
          {singleSkuStock && (
            <SingleSkuStockRegion stock={singleSkuStock} stockTotal={deal.stockTotal} />
          )}
          {/* Timer slot — always rendered to avoid layout shift on hydration */}
          {secondsLeft == null ? (
            /* Pre-mount placeholder: spinner keeps slot height, prevents pop-in flash */
            <div className="text-text-muted flex items-center gap-1 text-xs" role="status">
              <span
                className="border-text-muted/30 border-t-text-muted h-3 w-3 animate-spin rounded-full border motion-reduce:animate-none"
                aria-hidden
              />
            </div>
          ) : isExpired ? (
            <div className="bg-surface-subtle text-text-muted inline-flex items-center gap-1 rounded-full px-2 py-1 text-xs font-medium">
              <span aria-hidden>•</span>
              <span>{t('deal_ended')}</span>
            </div>
          ) : (
            <div
              className={cn(
                'flex items-center gap-1 text-xs',
                !countdown!.hasWords && 'tabular-nums',
                stage === 'hot'
                  ? 'text-danger-600 font-semibold'
                  : stage === 'warm'
                    ? 'text-danger-500'
                    : 'text-text-muted',
              )}
            >
              <span aria-hidden>⏱</span>
              {countdown!.hasWords ? (
                <>
                  <span>{t('closes_in')}</span>
                  <span
                    dir="rtl"
                    className={
                      locale === 'he'
                        ? 'font-[family-name:var(--font-he)]'
                        : 'font-[family-name:var(--font-en)]'
                    }
                  >
                    {countdown!.text}
                  </span>
                </>
              ) : (
                <>
                  <span dir="ltr" className="font-[family-name:var(--font-en)]">
                    {countdown!.text}
                  </span>
                  <span>{t('closes_in')}</span>
                </>
              )}
            </div>
          )}
        </div>
      </div>
    </a>
  );
}

function SingleSkuDealCard(props: DealCardProps) {
  const stock = useDealStock(props.deal.id, { enabled: !props.demo });
  if (stock.status === 'resolved' && stock.soldOut) return null;
  return <DealCardContent {...props} singleSkuStock={stock} />;
}

function DealCardInner(props: DealCardProps) {
  const hasAxes = (props.deal.axesCount ?? 0) > 0;
  if (!hasAxes) return <SingleSkuDealCard {...props} />;
  return <DealCardContent {...props} singleSkuStock={null} />;
}

export const DealCard = React.memo(DealCardInner);
