import { useCallback, useEffect, useRef, useState } from 'react';
import GlassSurface from '../ui/GlassSurface.js';
import ScannerToast from './ScannerToast.js';
import ScannerCountPill from './ScannerCountPill.js';
import ScannerScanPeek from './ScannerScanPeek.js';
import ScannerDisambiguation from './ScannerDisambiguation.js';
import { useScannerSound } from '../../lib/use-scanner-sound.js';
import { useScannerFlash } from '../../lib/use-scanner-flash.js';
import {
  cardGuideToContainerStyle,
  computeObjectCoverLayout,
  layoutGuideToVideoBounds,
  videoBoundsToContainerStyle,
} from '../../lib/scanner-video-layout.js';

const TOAST_DURATION_MS = 2500;

function CardGuideFrame({ layout, onTap, isManualMode, isIdentifying, tapDisabled }) {
  if (!layout) return null;

  const style = cardGuideToContainerStyle(layout);
  const className = [
    'absolute scan-guide',
    isManualMode ? 'scan-guide-tappable' : 'pointer-events-none',
    isIdentifying ? 'scan-guide-active' : '',
  ]
    .filter(Boolean)
    .join(' ');

  const frame = (
    <>
      <span className="scan-bracket scan-bracket-tl" />
      <span className="scan-bracket scan-bracket-tr" />
      <span className="scan-bracket scan-bracket-bl" />
      <span className="scan-bracket scan-bracket-br" />
      <style jsx>{`
        .scan-guide {
          transition: box-shadow 0.2s ease, transform 0.15s ease;
        }
        .scan-guide-tappable {
          cursor: pointer;
          touch-action: manipulation;
        }
        .scan-guide-tappable:active:not(:disabled) {
          transform: scale(0.985);
        }
        .scan-guide-active {
          box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-flame) 55%, transparent);
        }
        .scan-bracket {
          position: absolute;
          width: 28px;
          height: 28px;
          border-color: color-mix(in srgb, var(--text-primary) 70%, transparent);
          border-style: solid;
        }
        .scan-guide-active .scan-bracket {
          border-color: var(--accent-ember);
        }
        .scan-bracket-tl { top: 0; left: 0; border-width: 2px 0 0 2px; }
        .scan-bracket-tr { top: 0; right: 0; border-width: 2px 2px 0 0; }
        .scan-bracket-bl { bottom: 0; left: 0; border-width: 0 0 2px 2px; }
        .scan-bracket-br { bottom: 0; right: 0; border-width: 0 2px 2px 0; }
      `}</style>
    </>
  );

  if (!isManualMode) {
    return (
      <div className={className} aria-hidden="true" style={style}>
        {frame}
      </div>
    );
  }

  return (
    <button
      type="button"
      className={className}
      style={{ ...style, background: 'transparent', padding: 0, border: 'none' }}
      onClick={onTap}
      disabled={tapDisabled}
      aria-label="Tap to scan card in frame"
      aria-busy={isIdentifying || undefined}
    >
      {frame}
    </button>
  );
}

function DetectionFrame({ card, layout }) {
  const label =
    card.status === 'scanned'
      ? `Card ${card.id} scanned`
      : `Card ${card.id} identified`;

  if (!layout) return null;

  const style = videoBoundsToContainerStyle(card.bounds, layout);

  return (
    <div
      className="absolute pointer-events-none scan-frame"
      role="status"
      aria-live="polite"
      aria-label={label}
      style={style}
    >
      <span className="scan-bracket scan-bracket-tl" aria-hidden="true" />
      <span className="scan-bracket scan-bracket-tr" aria-hidden="true" />
      <span className="scan-bracket scan-bracket-bl" aria-hidden="true" />
      <span className="scan-bracket scan-bracket-br" aria-hidden="true" />
      <span className="scan-line" aria-hidden="true" />
      <style jsx>{`
        .scan-bracket {
          position: absolute;
          width: 22px;
          height: 22px;
          border-color: var(--accent-ember);
          border-style: solid;
          filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent-flame) 55%, transparent));
        }
        .scan-bracket-tl { top: 0; left: 0; border-width: 3px 0 0 3px; }
        .scan-bracket-tr { top: 0; right: 0; border-width: 3px 3px 0 0; }
        .scan-bracket-bl { bottom: 0; left: 0; border-width: 0 0 3px 3px; }
        .scan-bracket-br { bottom: 0; right: 0; border-width: 0 3px 3px 0; }
        .scan-line {
          position: absolute;
          left: 8%;
          right: 8%;
          height: 2px;
          top: 0;
          background: linear-gradient(
            90deg,
            transparent,
            var(--accent-ember),
            var(--accent-flame),
            var(--accent-ember),
            transparent
          );
          box-shadow: 0 0 10px color-mix(in srgb, var(--accent-flame) 70%, transparent);
          animation: scan-sweep 1.6s var(--motion-ease-linear, linear) infinite;
        }
        @keyframes scan-sweep {
          0% { top: 8%; opacity: 0.35; }
          50% { top: 88%; opacity: 1; }
          100% { top: 8%; opacity: 0.35; }
        }
        @media (prefers-reduced-motion: reduce) {
          .scan-line {
            animation: none;
            top: 50%;
            opacity: 0.85;
          }
        }
      `}</style>
    </div>
  );
}

function ShutterButton({ onClick, busy, label = 'Scan card' }) {
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={busy}
      className="relative w-14 h-14 rounded-full flex items-center justify-center flex-shrink-0 transition-transform active:scale-95 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-60"
      style={{
        minWidth: 56,
        minHeight: 56,
        backgroundColor: 'color-mix(in srgb, var(--text-primary) 12%, transparent)',
        border: '3px solid var(--text-primary)',
        '--tw-ring-color': 'var(--accent-ember)',
        '--tw-ring-offset-color': 'transparent',
      }}
      aria-label={label}
      aria-busy={busy || undefined}
    >
      {busy ? (
        <div
          className="w-5 h-5 rounded-full border-2 border-t-transparent animate-spin"
          style={{ borderColor: 'var(--accent-ember)', borderTopColor: 'transparent' }}
          aria-hidden="true"
        />
      ) : (
        <span
          className="w-10 h-10 rounded-full"
          style={{ backgroundColor: 'var(--text-primary)' }}
          aria-hidden="true"
        />
      )}
    </button>
  );
}

function ChromeIconButton({
  onClick,
  label,
  pressed,
  busy,
  children,
  className = '',
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={`w-11 h-11 rounded-full flex items-center justify-center transition-transform active:scale-95 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 ${className}`}
      style={{
        minWidth: 44,
        minHeight: 44,
        '--tw-ring-color': 'var(--accent-ember)',
        '--tw-ring-offset-color': 'transparent',
      }}
      aria-label={label}
      aria-pressed={pressed}
      aria-busy={busy || undefined}
      disabled={busy}
    >
      <GlassSurface
        as="span"
        tint="mid"
        rim="subtle"
        blur="mid"
        className="w-full h-full rounded-full flex items-center justify-center"
        style={{ color: 'var(--text-primary)' }}
      >
        {children}
      </GlassSurface>
    </button>
  );
}

function CameraViewport({
  viewportRef,
  videoRef,
  isStreaming,
  displayLayout,
  foundCards,
  isManualMode,
  isIdentifying,
  onGuideTap,
  manualScanDisabled,
}) {
  return (
    <div
      ref={viewportRef}
      className="absolute inset-0"
      style={{ backgroundColor: 'var(--bg-tertiary)' }}
    >
      <video
        ref={videoRef}
        className="absolute inset-0 w-full h-full object-cover"
        style={{ display: isStreaming ? 'block' : 'none' }}
        autoPlay
        playsInline
        muted
        aria-label="Card scanner camera feed"
      />

      {isStreaming && displayLayout && (
        <CardGuideFrame
          layout={displayLayout}
          isManualMode={isManualMode}
          isIdentifying={isIdentifying}
          onTap={onGuideTap}
          tapDisabled={manualScanDisabled}
        />
      )}

      {isStreaming &&
        displayLayout &&
        foundCards.map((card) => (
          <DetectionFrame key={card.id} card={card} layout={displayLayout} />
        ))}

      {!isStreaming && (
        <div className="absolute inset-0 flex items-center justify-center">
          <div className="flex flex-col items-center gap-3">
            <div
              className="w-10 h-10 rounded-full border-2 border-t-transparent animate-spin"
              style={{ borderColor: 'var(--accent-ember)', borderTopColor: 'transparent' }}
              aria-hidden="true"
            />
            <span
              className="text-sm font-medium"
              style={{ color: 'var(--text-secondary)' }}
            >
              Starting camera…
            </span>
          </div>
        </div>
      )}
    </div>
  );
}

export default function ScannerCamera({
  queue,
  camera,
  identification,
  onBack = () => {},
  onOpenCheckout = () => {},
  onGalleryIdentify,
  latestPeekCard = null,
  cartCount,
  isCheckoutOpen = false,
  verificationPausedRef,
  variant = 'default',
  autoDetectOn = true,
}) {
  const isWorkstation = variant === 'workstation';
  const [toast, setToast] = useState({ message: '', visible: false, type: 'success' });
  const [galleryBusy, setGalleryBusy] = useState(false);
  const toastTimerRef = useRef(null);
  const prevCountRef = useRef(queue.scannedCards?.length ?? 0);
  const galleryInputRef = useRef(null);
  const viewportRef = useRef(null);
  const [viewportSize, setViewportSize] = useState({ width: 0, height: 0 });

  const {
    videoRef,
    canvasRef,
    detectionCanvasRef,
    isStreaming,
    trackedCards,
    videoMetrics,
    startCamera,
    streamRef,
    facingMode,
    switchFacingMode,
    triggerManualScan,
  } = camera;

  const isIdentifying = Boolean(identification.isIdentifying);
  const isManualMode = !autoDetectOn;
  const manualScanDisabled = isIdentifying || isCheckoutOpen || Boolean(identification.disambiguation);

  const sound = useScannerSound();
  const flash = useScannerFlash(streamRef);

  const resolvedCartCount = cartCount ?? queue.scannedCards?.length ?? 0;

  useEffect(() => {
    startCamera();
    // eslint-disable-next-line react-hooks/exhaustive-deps -- one-shot mount
  }, []);

  useEffect(() => {
    const node = viewportRef.current;
    if (!node) return undefined;

    const syncSize = () => {
      setViewportSize({
        width: node.clientWidth,
        height: node.clientHeight,
      });
    };

    syncSize();
    const observer = new ResizeObserver(syncSize);
    observer.observe(node);

    return () => observer.disconnect();
  }, []);

  const currentCount = queue.scannedCards?.length ?? 0;
  useEffect(() => {
    if (currentCount > prevCountRef.current) {
      const newest = queue.scannedCards[0];
      const cardName = newest?.name || newest?.card?.name || 'Card';

      navigator.vibrate?.(50);
      sound.playSuccess();

      clearTimeout(toastTimerRef.current);
      setToast({ message: `${cardName} added`, visible: true, type: 'success' });
      toastTimerRef.current = setTimeout(() => {
        setToast((t) => ({ ...t, visible: false }));
      }, TOAST_DURATION_MS);
    }
    prevCountRef.current = currentCount;
  }, [currentCount]); // eslint-disable-line react-hooks/exhaustive-deps -- intentionally only reacts to count

  useEffect(() => {
    return () => clearTimeout(toastTimerRef.current);
  }, []);

  useEffect(() => {
    if (facingMode === 'user' && flash.flashOn) {
      flash.toggleFlash();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- only react to facing mode changes
  }, [facingMode]);

  const handleGalleryClick = useCallback(() => {
    galleryInputRef.current?.click();
  }, []);

  const handleGalleryChange = useCallback(
    async (event) => {
      const file = event.target.files?.[0];
      event.target.value = '';
      if (!file) return;

      const identify =
        onGalleryIdentify ||
        identification.identifyFromGalleryFile?.bind(identification);

      if (!identify) return;

      setGalleryBusy(true);
      try {
        await identify(file);
      } finally {
        setGalleryBusy(false);
      }
    },
    [identification, onGalleryIdentify]
  );

  const foundCards = trackedCards.filter(
    (c) => c.status === 'confirmed' || c.status === 'scanned'
  );

  const hasMetrics = videoMetrics.width > 0 && videoMetrics.height > 0;
  const displayLayout =
    hasMetrics && viewportSize.width > 0 && viewportSize.height > 0
      ? computeObjectCoverLayout(
          videoMetrics.width,
          videoMetrics.height,
          viewportSize.width,
          viewportSize.height
        )
      : null;

  const handleManualScan = useCallback(() => {
    if (manualScanDisabled || !triggerManualScan) return;

    const guideBounds = displayLayout ? layoutGuideToVideoBounds(displayLayout) : null;
    const result = triggerManualScan(guideBounds);

    if (result?.ok) {
      navigator.vibrate?.(30);
      return;
    }

    if (result?.reason === 'no_card') {
      clearTimeout(toastTimerRef.current);
      setToast({ message: 'Hold the card in the frame', visible: true, type: 'info' });
      toastTimerRef.current = setTimeout(() => {
        setToast((current) => ({ ...current, visible: false }));
      }, TOAST_DURATION_MS);
    }
  }, [displayLayout, manualScanDisabled, triggerManualScan]);

  const showFlash = flash.flashSupported && facingMode === 'environment';
  const scanStatus = (() => {
    if (isCheckoutOpen) return 'Checkout open';
    if (!isStreaming) return 'Starting camera…';
    if (isIdentifying) return 'Identifying card…';
    if (isManualMode) return 'Tap frame or scan button';
    return 'Scanning…';
  })();

  const switchCameraLabel =
    facingMode === 'environment' ? 'Switch to front camera' : 'Switch to rear camera';

  return (
    <div
      className={`relative w-full overflow-hidden ${
        isWorkstation
          ? 'md:rounded-xl md:aspect-video md:min-h-0 md:max-h-[min(56vh,640px)]'
          : 'min-h-[100dvh] max-md:rounded-none max-md:min-h-[100dvh]'
      }`}
    >
      {isWorkstation ? (
        <GlassSurface
          tint="low"
          rim="subtle"
          blur="mid"
          className="absolute inset-0 md:rounded-xl overflow-hidden"
          style={{ boxShadow: 'var(--rim-light-inner), var(--ember-rim-subtle)' }}
        >
          <CameraViewport
            viewportRef={viewportRef}
            videoRef={videoRef}
            isStreaming={isStreaming}
            displayLayout={displayLayout}
            foundCards={foundCards}
            isManualMode={isManualMode}
            isIdentifying={isIdentifying}
            onGuideTap={handleManualScan}
            manualScanDisabled={manualScanDisabled}
          />
        </GlassSurface>
      ) : (
        <CameraViewport
          viewportRef={viewportRef}
          videoRef={videoRef}
          isStreaming={isStreaming}
          displayLayout={displayLayout}
          foundCards={foundCards}
          isManualMode={isManualMode}
          isIdentifying={isIdentifying}
          onGuideTap={handleManualScan}
          manualScanDisabled={manualScanDisabled}
        />
      )}

      {isStreaming && (
        <div className={`absolute top-3 right-3 z-10 ${isWorkstation ? 'md:hidden' : ''}`}>
          <GlassSurface
            tint="mid"
            rim="subtle"
            blur="mid"
            className="flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold shadow-lg"
            style={{ color: 'var(--text-primary)' }}
          >
            <span
              className="w-1.5 h-1.5 rounded-full animate-pulse"
              style={{ backgroundColor: 'var(--color-error)' }}
              aria-hidden="true"
            />
            LIVE
          </GlassSurface>
        </div>
      )}

      {isWorkstation && isStreaming && (
        <div className="absolute top-3 left-3 z-10 hidden md:block">
          <GlassSurface
            tint="mid"
            rim="subtle"
            blur="mid"
            className="flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold shadow-lg"
            style={{ color: 'var(--text-primary)' }}
            role="status"
            aria-live="polite"
          >
            <span
              className={`w-1.5 h-1.5 rounded-full ${autoDetectOn ? 'motion-safe:animate-pulse' : ''}`}
              style={{
                backgroundColor: autoDetectOn
                  ? 'var(--color-success)'
                  : 'var(--text-secondary)',
              }}
              aria-hidden="true"
            />
            Auto-detect {autoDetectOn ? 'ON' : 'OFF'}
          </GlassSurface>
        </div>
      )}

      <ScannerToast
        message={toast.message}
        visible={toast.visible}
        type={toast.type}
      />

      <div className={isWorkstation ? 'md:hidden' : undefined}>
        <ScannerScanPeek
          key={latestPeekCard?.id ?? latestPeekCard?.name ?? 'peek'}
          card={latestPeekCard}
          onOpenCheckout={onOpenCheckout}
        />
      </div>

      <div
        className={`absolute top-0 left-0 right-0 z-30 px-3 pb-2 ${isWorkstation ? 'md:hidden' : ''}`}
        style={{ paddingTop: 'calc(0.75rem + env(safe-area-inset-top, 0px))' }}
      >
        <GlassSurface
          tint="mid"
          rim="subtle"
          blur="mid"
          className="flex items-center justify-between gap-2 rounded-2xl px-2 py-2"
        >
          <ChromeIconButton onClick={onBack} label="Leave scanner">
            <svg
              width="18"
              height="18"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2"
              strokeLinecap="round"
              strokeLinejoin="round"
              aria-hidden="true"
            >
              <path d="M19 12H5" />
              <path d="M12 19l-7-7 7-7" />
            </svg>
          </ChromeIconButton>

          <h1
            className="text-base font-semibold truncate"
            style={{ color: 'var(--text-primary)' }}
          >
            Scan Cards
          </h1>

          <ChromeIconButton
            onClick={handleGalleryClick}
            label="Choose image from gallery"
            busy={galleryBusy}
          >
            {galleryBusy ? (
              <div
                className="w-4 h-4 rounded-full border-2 border-t-transparent animate-spin"
                style={{ borderColor: 'var(--accent-ember)', borderTopColor: 'transparent' }}
                aria-hidden="true"
              />
            ) : (
              <svg
                width="18"
                height="18"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
                aria-hidden="true"
              >
                <rect x="3" y="3" width="18" height="18" rx="2" />
                <circle cx="8.5" cy="8.5" r="1.5" />
                <path d="M21 15l-5-5L5 21" />
              </svg>
            )}
          </ChromeIconButton>
        </GlassSurface>
      </div>

      <input
        ref={galleryInputRef}
        type="file"
        accept="image/*"
        className="sr-only"
        tabIndex={-1}
        onChange={handleGalleryChange}
      />

      {isStreaming && (
        <div
          className={`absolute bottom-0 left-0 right-0 z-30 px-3 pt-2 ${isWorkstation ? 'md:hidden' : ''}`}
          style={{ paddingBottom: 'calc(0.75rem + env(safe-area-inset-bottom, 0px))' }}
        >
          <GlassSurface
            tint="mid"
            rim="subtle"
            blur="mid"
            className="flex items-center justify-between gap-2 rounded-2xl px-2 py-2"
          >
            <div className="flex items-center gap-2">
              {showFlash ? (
                <ChromeIconButton
                  onClick={flash.toggleFlash}
                  label={flash.flashOn ? 'Turn off flash' : 'Turn on flash'}
                  pressed={flash.flashOn}
                  className={flash.flashOn ? 'ring-2' : ''}
                >
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                    <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />
                  </svg>
                </ChromeIconButton>
              ) : (
                <ChromeIconButton onClick={switchFacingMode} label={switchCameraLabel}>
                  <svg
                    width="18"
                    height="18"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    aria-hidden="true"
                  >
                    <path d="M11 19H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h6" />
                    <path d="M13 5h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-6" />
                    <path d="M8 12h8" />
                    <path d="m16 9 3 3-3 3" />
                    <path d="m8 15-3-3 3-3" />
                  </svg>
                </ChromeIconButton>
              )}

              {showFlash && (
                <ChromeIconButton onClick={switchFacingMode} label={switchCameraLabel}>
                  <svg
                    width="18"
                    height="18"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    aria-hidden="true"
                  >
                    <path d="M11 19H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h6" />
                    <path d="M13 5h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-6" />
                    <path d="M8 12h8" />
                    <path d="m16 9 3 3-3 3" />
                    <path d="m8 15-3-3 3-3" />
                  </svg>
                </ChromeIconButton>
              )}
            </div>

            {isManualMode && !isWorkstation ? (
              <div className="flex flex-col items-center gap-1 flex-shrink-0 px-1">
                <ShutterButton
                  onClick={handleManualScan}
                  busy={isIdentifying}
                  label={isIdentifying ? 'Identifying card' : 'Scan card'}
                />
                <span
                  className="text-[10px] font-medium text-center max-w-[88px] leading-tight"
                  style={{ color: 'var(--text-secondary)' }}
                  aria-live="polite"
                >
                  {scanStatus}
                </span>
              </div>
            ) : (
              <p
                className="text-xs font-medium truncate text-center flex-1 px-1"
                style={{ color: 'var(--text-secondary)' }}
                aria-live="polite"
              >
                {scanStatus}
              </p>
            )}

            <div className="flex flex-1 min-w-0 justify-end">
              <ScannerCountPill
                count={resolvedCartCount}
                onOpenCheckout={onOpenCheckout}
              />
            </div>
          </GlassSurface>
        </div>
      )}

      <canvas ref={canvasRef} className="hidden" aria-hidden="true" />
      <canvas ref={detectionCanvasRef} className="hidden" aria-hidden="true" />

      {identification.disambiguation && (
        <ScannerDisambiguation
          disambiguation={identification.disambiguation}
          submittingReview={identification.submittingReview}
          onPick={identification.handleDisambiguationPick}
          onNotInCatalog={identification.handleNotInCatalog}
          onCancel={identification.cancelDisambiguation}
        />
      )}
    </div>
  );
}
