// @design-system: feedback/Spinner
'use client';
import { useContext } from 'react';
import { cn } from '@/lib/cn';
import { useT } from '@/lib/i18n/react';
import { MDLogo } from '@/components/ui/icons/MDLogo';
import { SpinnerVariantContext } from './RouteSpinnerProvider';

export type SpinnerVariant = 'bounce' | 'dots' | 'bar' | 'spot' | 'inline' | 'pulse' | 'stack';

export interface SpinnerProps {
  variant?: SpinnerVariant;
  size?: 'sm' | 'md' | 'lg';
  /** Accessible label. Defaults to the translated loading string. */
  label?: string;
  className?: string;
}

/** Mark px per size for bounce/stack variants */
const markSizeMap = { sm: 24, md: 56, lg: 80 } as const;
/** Container min-px for non-inline variants */
const containerSizeMap = { sm: 48, md: 96, lg: 140 } as const;

/* ─── bounce ─────────────────────────────────────────────────── */
function SpinnerBounce({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const markPx = markSizeMap[size];
  const jump = Math.round(markPx * 0.55);
  return (
    <div
      style={
        {
          display: 'flex',
          alignItems: 'flex-end',
          gap: Math.round(markPx * 0.3),
          '--mdsp-jump': `${jump}px`,
        } as React.CSSProperties
      }
      aria-hidden="true"
    >
      {([0, 1, 2] as const).map((i) => (
        <div key={i} className="flex flex-col items-center gap-1">
          <div className={`mdsp-bounce-mark mdsp-bounce-mark--${i} shrink-0`}>
            <MDLogo size={markPx} title="" />
          </div>
          <div
            className={`mdsp-bounce-shadow mdsp-bounce-shadow--${i}`}
            style={{
              width: Math.round(markPx * 0.7),
              height: 4,
              borderRadius: '50%',
              background: 'var(--color-brand-primary-900)',
              opacity: 0.15,
            }}
          />
        </div>
      ))}
    </div>
  );
}

/* ─── dots ───────────────────────────────────────────────────── */
function SpinnerDots({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const logoPx = size === 'sm' ? 32 : size === 'lg' ? 64 : 48;
  return (
    <div className="flex flex-col items-center gap-2.5" aria-hidden="true">
      <MDLogo size={logoPx} title="" />
      <div className="flex items-center gap-1.5">
        {([0, 1, 2] as const).map((i) => (
          <div
            key={i}
            className={`mdsp-dot mdsp-dot--${i}`}
            style={{
              width: 6,
              height: 6,
              borderRadius: '50%',
              background: 'var(--color-brand-primary-700)',
              flexShrink: 0,
            }}
          />
        ))}
      </div>
    </div>
  );
}

/* ─── bar ────────────────────────────────────────────────────── */
function SpinnerBar({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const logoPx = size === 'sm' ? 32 : size === 'lg' ? 64 : 48;
  const barW = size === 'lg' ? 200 : 150;
  const barH = size === 'lg' ? 6 : 5;
  return (
    <div className="flex flex-col items-center gap-2.5" aria-hidden="true">
      <MDLogo size={logoPx} title="" />
      <div
        style={{
          width: barW,
          height: barH,
          borderRadius: Math.round(barH / 2),
          background: 'var(--color-neutral-200)',
          overflow: 'hidden',
          position: 'relative',
        }}
      >
        <div
          className="mdsp-bar-fill"
          style={{
            position: 'absolute',
            inset: 0,
            background: 'var(--gradient-brand-accent)',
            transformOrigin: '0% 50%',
          }}
        />
      </div>
    </div>
  );
}

/* ─── spot ───────────────────────────────────────────────────── */
function SpinnerSpot({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const outer = size === 'sm' ? 56 : size === 'lg' ? 120 : 80;
  const inner = Math.round(outer * 0.78);
  const logoPx = Math.round(outer * 0.42);
  const stroke = Math.max(4, Math.round(outer * 0.06));
  const r = outer / 2 - stroke / 2;
  const circ = 2 * Math.PI * r;
  return (
    <div
      style={{ position: 'relative', width: outer, height: outer, flexShrink: 0 }}
      aria-hidden="true"
    >
      <svg width={outer} height={outer} className="mdsp-spot-svg block">
        <circle
          cx={outer / 2}
          cy={outer / 2}
          r={r}
          fill="none"
          stroke="var(--color-brand-primary-100)"
          strokeWidth={stroke}
        />
        <circle
          cx={outer / 2}
          cy={outer / 2}
          r={r}
          fill="none"
          stroke="var(--color-brand-primary-700)"
          strokeWidth={stroke}
          strokeLinecap="round"
          strokeDasharray={`${circ * 0.25} ${circ}`}
        />
      </svg>
      <div
        style={{
          position: 'absolute',
          inset: Math.round((outer - inner) / 2),
          borderRadius: '50%',
          background: 'var(--color-surface-base)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          boxShadow: 'inset 0 0 0 1px var(--color-brand-primary-100)',
        }}
      >
        <MDLogo size={logoPx} title="" />
      </div>
    </div>
  );
}

/* ─── inline ─────────────────────────────────────────────────── */
function SpinnerInline() {
  return (
    <div className="inline-flex items-center gap-0.5" aria-hidden="true">
      {([0, 1, 2] as const).map((i) => (
        <div
          key={i}
          className={`mdsp-dot mdsp-dot--${i}`}
          style={{
            width: 4,
            height: 4,
            borderRadius: '50%',
            background: 'var(--color-brand-primary-700)',
            flexShrink: 0,
          }}
        />
      ))}
    </div>
  );
}

/* ─── pulse ──────────────────────────────────────────────────── */
function SpinnerPulse({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const outer = size === 'sm' ? 56 : size === 'lg' ? 120 : 80;
  const logoPx = Math.round(outer * 0.6);
  return (
    <div
      style={{
        position: 'relative',
        width: outer * 1.6,
        height: outer * 1.6,
        display: 'grid',
        placeItems: 'center',
        flexShrink: 0,
      }}
      aria-hidden="true"
    >
      {([0, 1, 2] as const).map((i) => (
        <div
          key={i}
          className={`mdsp-pulse-ring mdsp-pulse-ring--${i}`}
          style={{
            position: 'absolute',
            width: outer,
            height: outer,
            borderRadius: '50%',
            border: '2px solid var(--color-brand-primary-500)',
          }}
        />
      ))}
      <div className="relative z-[2]">
        <MDLogo size={logoPx} title="" />
      </div>
    </div>
  );
}

/* ─── stack ──────────────────────────────────────────────────── */
function SpinnerStack({ size }: { size: 'sm' | 'md' | 'lg' }) {
  const markPx = size === 'sm' ? 28 : size === 'lg' ? 56 : 44;
  const offset = Math.round(markPx * 0.6);
  return (
    <div
      style={
        {
          position: 'relative',
          width: markPx * 2.2,
          height: markPx * 1.4,
          display: 'grid',
          placeItems: 'center',
          flexShrink: 0,
          '--mdsp-stack-offset': `${offset}px`,
        } as React.CSSProperties
      }
      aria-hidden="true"
    >
      {([0, 1, 2] as const).map((i) => (
        <div key={i} className={`mdsp-stack mdsp-stack--${i} absolute inline-flex`}>
          <MDLogo size={markPx} title="" />
        </div>
      ))}
    </div>
  );
}

/* ─── Main Spinner ───────────────────────────────────────────── */
export function Spinner({ variant, size = 'md', label, className }: SpinnerProps) {
  const contextVariant = useContext(SpinnerVariantContext);
  const resolvedVariant: SpinnerVariant = variant ?? contextVariant ?? 'bounce';
  const containerPx = resolvedVariant === 'inline' ? undefined : containerSizeMap[size];
  const tCommon = useT('common');
  const defaultLabel = tCommon('loading');

  return (
    <div
      role="status"
      aria-label={label ?? defaultLabel}
      data-variant={resolvedVariant}
      className={cn('inline-flex items-center justify-center', className)}
      style={containerPx ? { minWidth: containerPx, minHeight: containerPx } : undefined}
    >
      <span className="sr-only">{label ?? defaultLabel}</span>
      {resolvedVariant === 'bounce' && <SpinnerBounce size={size} />}
      {resolvedVariant === 'dots' && <SpinnerDots size={size} />}
      {resolvedVariant === 'bar' && <SpinnerBar size={size} />}
      {resolvedVariant === 'spot' && <SpinnerSpot size={size} />}
      {resolvedVariant === 'inline' && <SpinnerInline />}
      {resolvedVariant === 'pulse' && <SpinnerPulse size={size} />}
      {resolvedVariant === 'stack' && <SpinnerStack size={size} />}
      <style>{`
        /* ── reduced motion ── */
        @media (prefers-reduced-motion: reduce) {
          .mdsp-bounce-mark,
          .mdsp-bounce-shadow,
          .mdsp-dot,
          .mdsp-bar-fill,
          .mdsp-spot-svg,
          .mdsp-pulse-ring,
          .mdsp-stack { animation: none !important; }
        }

        /* ── bounce variant (proportional jump + ground shadow) ── */
        @keyframes mdsp-bounce {
          0%, 100% { transform: translateY(0); }
          40%      { transform: translateY(calc(var(--mdsp-jump) * -1)); }
        }
        @keyframes mdsp-bounce-shadow {
          0%, 100% { transform: scaleX(1); opacity: 0.18; }
          40%      { transform: scaleX(0.55); opacity: 0.07; }
        }
        .mdsp-bounce-mark {
          animation: mdsp-bounce 1.05s cubic-bezier(.4,0,.2,1) infinite;
        }
        .mdsp-bounce-mark--1 { animation-delay: 0.14s; }
        .mdsp-bounce-mark--2 { animation-delay: 0.28s; }
        .mdsp-bounce-shadow {
          animation: mdsp-bounce-shadow 1.05s cubic-bezier(.4,0,.2,1) infinite;
          transform-origin: center;
        }
        .mdsp-bounce-shadow--1 { animation-delay: 0.14s; }
        .mdsp-bounce-shadow--2 { animation-delay: 0.28s; }

        /* ── dots & inline variant ── */
        @keyframes mdsp-dot-bounce {
          0%, 100% { transform: translateY(0); opacity: 0.5; }
          40%      { transform: translateY(-6px); opacity: 1; }
        }
        .mdsp-dot {
          animation: mdsp-dot-bounce 1s ease-in-out infinite;
        }
        .mdsp-dot--1 { animation-delay: 0.15s; }
        .mdsp-dot--2 { animation-delay: 0.3s; }

        /* ── bar variant ── */
        @keyframes mdsp-bar-slide {
          0%   { transform: translateX(-100%); }
          50%  { transform: translateX(0%); }
          100% { transform: translateX(100%); }
        }
        .mdsp-bar-fill {
          animation: mdsp-bar-slide 1.4s ease-in-out infinite;
        }

        /* ── spot variant (single bright arc on soft track) ── */
        @keyframes mdsp-spot-rotate {
          from { transform: rotate(0deg); }
          to   { transform: rotate(360deg); }
        }
        .mdsp-spot-svg {
          animation: mdsp-spot-rotate 1.4s linear infinite;
          transform-origin: center;
        }
        :dir(rtl) .mdsp-spot-svg {
          animation-direction: reverse;
        }

        /* ── pulse variant ── */
        @keyframes mdsp-pulse-ring {
          0%   { transform: scale(0.6); opacity: 0.75; }
          100% { transform: scale(1.8); opacity: 0; }
        }
        .mdsp-pulse-ring {
          animation: mdsp-pulse-ring 2.1s ease-out infinite;
        }
        .mdsp-pulse-ring--1 { animation-delay: 0.7s; }
        .mdsp-pulse-ring--2 { animation-delay: 1.4s; }

        /* ── stack variant ── */
        @keyframes mdsp-stack-kf {
          0%   { transform: translate(calc(var(--mdsp-stack-offset) * -1), 0) scale(0.85); opacity: 0; }
          20%  { transform: translate(calc(var(--mdsp-stack-offset) * -1), 0) scale(0.85); opacity: 1; }
          50%  { transform: translate(0, 0) scale(1); opacity: 1; }
          80%  { transform: translate(var(--mdsp-stack-offset), 0) scale(0.85); opacity: 1; }
          100% { transform: translate(var(--mdsp-stack-offset), 0) scale(0.85); opacity: 0; }
        }
        .mdsp-stack {
          animation: mdsp-stack-kf 1.6s ease-in-out infinite;
        }
        .mdsp-stack--1 { animation-delay: -0.53s; }
        .mdsp-stack--2 { animation-delay: -1.06s; }
      `}</style>
    </div>
  );
}
