// @design-system: domain/PostPurchaseReaction

'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import { cn } from '@/lib/cn';
import { Button } from '@/components/ui/primitives/Button';
import { Icon } from '@/components/ui/icons/Icon';
import { useT } from '@/lib/i18n/react';
import { useLocale } from '@/lib/i18n/react';
import { formatCurrency } from '@/lib/format';
import { captureCaught } from '@/lib/observability';
import { usePrefersReducedMotion } from '@/lib/hooks/useHydrated';

const FLOATING_FADE_MS = 60_000;
const FIRST_AUTO_DISMISS_MS = 10_000;

/** Props for PostPurchaseReaction */
export interface PostPurchaseReactionProps {
  /** Current total purchase count (determines mode). */
  purchaseCount: number;
  /** Whether the current user is a guest (not registered). */
  isGuest?: boolean;
  /** Total savings so far (used in floating mode). */
  totalSavings?: number;
  /** Number of new businesses discovered (used in floating mode). */
  newBusinesses?: number;
  /** Called when the component is dismissed. */
  onDismiss?: () => void;
  /** Called when the guest register prompt is clicked. */
  onRegister?: () => void;
  /** Additional class names (applies to the wrapper). */
  className?: string;
}

/**
 * PostPurchaseReaction - animated celebration component shown after each purchase.
 *
 * Modes by purchaseCount:
 * - 1 registered: confetti + first purchase text, auto-dismisses at 10s
 * - 1 guest: confetti + "great deal!" text + register prompt
 * - 2: text-only
 * - 3: text-only
 * - 4+: floating fixed widget, fades over 60s, draggable, tappable to restore
 *
 * All modes respect `prefers-reduced-motion`.
 *
 * @example
 * ```tsx
 * <PostPurchaseReaction purchaseCount={1} onDismiss={handleDismiss} />
 * ```
 */
export function PostPurchaseReaction({
  purchaseCount,
  isGuest = false,
  totalSavings = 0,
  newBusinesses = 0,
  onDismiss,
  onRegister,
  className,
}: PostPurchaseReactionProps) {
  const t = useT('domain_post_purchase');
  const { locale } = useLocale();
  const [dismissed, setDismissed] = useState(false);
  const [opacity, setOpacity] = useState(1);
  const [dragging, setDragging] = useState(false);
  const [pos, setPos] = useState({ x: 0, y: 0 });
  const dragRef = useRef<{
    startX: number;
    startY: number;
    startPosX: number;
    startPosY: number;
  } | null>(null);
  const confettiRef = useRef<boolean>(false);

  const prefersReducedMotion = usePrefersReducedMotion();

  const handleDismiss = useCallback(() => {
    setDismissed(true);
    onDismiss?.();
  }, [onDismiss]);

  // Auto-dismiss after 10s for first purchase
  useEffect(() => {
    if (purchaseCount !== 1 || dismissed) return;
    const id = setTimeout(handleDismiss, FIRST_AUTO_DISMISS_MS);
    return () => clearTimeout(id);
  }, [purchaseCount, dismissed, handleDismiss]);

  // Floating mode: fade to transparent over 60s
  useEffect(() => {
    if (purchaseCount < 4 || dismissed || prefersReducedMotion) return;
    const start = Date.now();
    const id = setInterval(() => {
      const elapsed = Date.now() - start;
      const newOpacity = Math.max(0, 1 - elapsed / FLOATING_FADE_MS);
      setOpacity(newOpacity);
      if (newOpacity === 0) clearInterval(id);
    }, 500);
    return () => clearInterval(id);
  }, [purchaseCount, dismissed, prefersReducedMotion]);

  // Confetti for first purchase
  useEffect(() => {
    if (purchaseCount !== 1 || confettiRef.current || prefersReducedMotion) return;
    confettiRef.current = true;
    import('canvas-confetti')
      .then((mod) => {
        const confetti = mod.default;
        confetti({
          particleCount: 120,
          spread: 80,
          origin: { y: 0.6 },
        });
      })
      .catch((err) => {
        captureCaught(err, {
          scope: 'components.ui.domain.PostPurchaseReaction',
          severity: 'info',
        });
      });
  }, [purchaseCount, prefersReducedMotion]);

  // Dragging for floating mode
  const handlePointerDown = useCallback(
    (e: React.PointerEvent<HTMLDivElement>) => {
      if (purchaseCount < 4) return;
      dragRef.current = {
        startX: e.clientX,
        startY: e.clientY,
        startPosX: pos.x,
        startPosY: pos.y,
      };
      setDragging(true);
      (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
    },
    [purchaseCount, pos],
  );

  const handlePointerMove = useCallback(
    (e: React.PointerEvent<HTMLDivElement>) => {
      if (!dragRef.current || !dragging) return;
      const dx = e.clientX - dragRef.current.startX;
      const dy = e.clientY - dragRef.current.startY;
      setPos({ x: dragRef.current.startPosX + dx, y: dragRef.current.startPosY + dy });
    },
    [dragging],
  );

  const handlePointerUp = useCallback(() => {
    dragRef.current = null;
    setDragging(false);
  }, []);

  const handleTap = useCallback(() => {
    if (purchaseCount >= 4) setOpacity(1);
  }, [purchaseCount]);

  if (dismissed) return null;

  // ── Floating widget (4+) ────────────────────────────────────────────────
  if (purchaseCount >= 4) {
    return (
      <div
        role="status"
        aria-live="polite"
        style={{
          opacity: prefersReducedMotion ? 1 : opacity,
          transform: `translate(${pos.x}px, ${pos.y}px)`,
          transition: dragging ? 'none' : 'opacity 0.5s ease',
        }}
        className={cn(
          'z-toast fixed end-4 bottom-20',
          'bg-brand-primary-700 w-56 rounded-xl p-4 shadow-xl',
          'text-brand-on-primary',
          'select-none',
          className,
        )}
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
      >
        {/* Restore opacity button - also supports arrow-key repositioning */}
        <button
          type="button"
          onClick={handleTap}
          onKeyDown={(e) => {
            const STEP = 20;
            const moves: Record<string, { dx: number; dy: number }> = {
              ArrowLeft: { dx: -STEP, dy: 0 },
              ArrowRight: { dx: STEP, dy: 0 },
              ArrowUp: { dx: 0, dy: -STEP },
              ArrowDown: { dx: 0, dy: STEP },
            };
            const move = moves[e.key];
            if (move) {
              e.preventDefault();
              setPos((prev) => ({ x: prev.x + move.dx, y: prev.y + move.dy }));
            }
          }}
          aria-label={t('floating_prefix') + purchaseCount}
          className={cn(
            'absolute inset-0 rounded-xl',
            'focus-visible:ring-brand-primary-300 focus-visible:ring-2 focus-visible:outline-none',
          )}
          style={{ cursor: dragging ? 'grabbing' : 'grab' }}
        />
        {/* Dismiss button */}
        <button
          type="button"
          onClick={(e) => {
            e.stopPropagation();
            handleDismiss();
          }}
          className="z-raised text-brand-primary-200 hover:text-brand-on-primary focus-visible:ring-brand-primary-300 absolute relative end-2 top-2 flex h-11 w-11 items-center justify-center rounded-full focus-visible:ring-2 focus-visible:outline-none"
          aria-label={t('dismiss')}
        >
          <Icon name="X" size="xs" />
        </button>
        <p className="z-raised relative text-sm font-semibold">
          {t('floating_prefix')}
          {purchaseCount}
        </p>
        <p className="z-raised text-brand-primary-200 relative mt-1 text-xs">
          {t('floating_saved')} {formatCurrency(totalSavings, locale)}
        </p>
        <p className="z-raised text-brand-primary-200 relative mt-0.5 text-xs">
          {newBusinesses} {t('floating_discovered')}
        </p>
      </div>
    );
  }

  // ── Inline banner (1-3) ──────────────────────────────────────────────────
  const messageMap: Record<number, string> = {
    1: isGuest ? t('first_guest') : t('first'),
    2: t('second'),
    3: t('third'),
  };
  const message = messageMap[purchaseCount] ?? t('first');

  return (
    <div
      role="status"
      aria-live="polite"
      className={cn(
        'border-brand-primary-200 bg-brand-primary-50 relative rounded-xl border p-5 text-center shadow-md',
        className,
      )}
    >
      <button
        type="button"
        onClick={handleDismiss}
        className="focus-visible:ring-brand-primary-500 absolute end-3 top-3 flex h-11 w-11 items-center justify-center rounded-full text-neutral-400 hover:bg-neutral-100 hover:text-neutral-700 focus-visible:ring-2 focus-visible:outline-none"
        aria-label={t('dismiss')}
      >
        <Icon name="X" size="xs" />
      </button>

      <p className="text-brand-primary-700 text-lg font-bold">{message}</p>

      {isGuest && purchaseCount === 1 && onRegister && (
        <Button variant="primary" size="sm" onClick={onRegister} className="mt-3">
          {t('first_guest_register')}
        </Button>
      )}
    </div>
  );
}
