import { useState, useEffect, useRef, useCallback } from 'react';
import { Spin, Empty, theme, Grid, Button, Modal, message } from 'antd';
import {
  LikeOutlined,
  LikeFilled,
  CommentOutlined,
  ShareAltOutlined,
  SoundOutlined,
  MutedOutlined,
  PlayCircleOutlined,
  ArrowUpOutlined,
  ArrowDownOutlined,
  CloseOutlined,
  CopyOutlined,
  MailOutlined,
  LinkOutlined,
  FullscreenOutlined,
  FullscreenExitOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
  EyeOutlined,
  MenuOutlined,
  CaretRightOutlined,
  RetweetOutlined,
} from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { mediaPublicApi, getOrCreateSessionId } from '@/lib/media-public-api';
import { MediaAuthProvider } from '@/contexts/MediaAuthContext';
import { useHls } from '@/lib/use-hls';
import LiveChat from '@/components/media/LiveChat';
import axios from 'axios';

const { useBreakpoint } = Grid;

interface ShortVideo {
  id: number;
  title: string | null;
  filename: string;
  durationSeconds: number | null;
  quality: string | null;
  orientation: string | null;
  thumbnailPath: string | null;
  thumbnailUrl: string | null;
  videoUrl: string | null;
  viewCount: number;
  upvoteCount: number;
  commentCount: number;
  width: number | null;
  height: number | null;
  // HLS adaptive bitrate state. When 'READY', the player uses the HLS manifest
  // for smoother streaming over restricted tunnels. Otherwise falls back to MP4.
  hlsStatus?: 'PENDING' | 'PROCESSING' | 'READY' | 'FAILED' | 'SKIPPED' | null;
}

interface ShortsResponse {
  shorts: ShortVideo[];
  pagination: {
    total: number;
    limit: number;
    offset: number;
    hasMore: boolean;
  };
}

const FETCH_SIZE = 20;
const PREFETCH_THRESHOLD = 5; // Fetch more when within 5 of the end

// Social share platform definitions
const SHARE_PLATFORMS = [
  {
    key: 'twitter',
    label: 'X (Twitter)',
    color: '#000',
    getUrl: (url: string, title: string) =>
      `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
  },
  {
    key: 'facebook',
    label: 'Facebook',
    color: '#1877F2',
    getUrl: (url: string) =>
      `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`,
  },
  {
    key: 'whatsapp',
    label: 'WhatsApp',
    color: '#25D366',
    getUrl: (url: string, title: string) =>
      `https://wa.me/?text=${encodeURIComponent(title + ' ' + url)}`,
  },
  {
    key: 'telegram',
    label: 'Telegram',
    color: '#0088cc',
    getUrl: (url: string, title: string) =>
      `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`,
  },
  {
    key: 'reddit',
    label: 'Reddit',
    color: '#FF4500',
    getUrl: (url: string, title: string) =>
      `https://reddit.com/submit?url=${encodeURIComponent(url)}&title=${encodeURIComponent(title)}`,
  },
  {
    key: 'email',
    label: 'Email',
    color: '#666',
    getUrl: (url: string, title: string) =>
      `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`,
  },
] as const;

export default function ShortsPage() {
  const { token } = theme.useToken();
  const screens = useBreakpoint();
  const isMobile = !screens.md;
  const navigate = useNavigate();

  const [shorts, setShorts] = useState<ShortVideo[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [currentIndex, setCurrentIndex] = useState(0);
  const [muted, setMuted] = useState(true);
  const [paused, setPaused] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [progress, setProgress] = useState(0);

  // Fullscreen mode — hides bottom info + orientation badge, keeps action bar
  const [isFullscreen, setIsFullscreen] = useState(false);

  // Action bar collapsed — hides all buttons, shows a small expand pill
  const [actionsCollapsed, setActionsCollapsed] = useState(false);

  // Zoom toggle — object-contain (fit) vs object-cover (fill)
  const [isZoomed, setIsZoomed] = useState(false);

  // Autoplay — advance to next video on end (vs loop)
  const [autoplay, setAutoplay] = useState(() =>
    localStorage.getItem('shorts_autoplay') === 'true'
  );

  // Chat bottom sheet state
  const [chatVideoId, setChatVideoId] = useState<number | null>(null);

  // Share modal state
  const [shareVideoId, setShareVideoId] = useState<number | null>(null);

  // Upvote state
  const [upvotedIds, setUpvotedIds] = useState<Set<number>>(new Set());
  const [upvoteCountOverrides, setUpvoteCountOverrides] = useState<Map<number, number>>(new Map());
  const [upvotingId, setUpvotingId] = useState<number | null>(null);

  // Comment count overrides (incremented locally when user submits)
  const [commentCountOverrides, setCommentCountOverrides] = useState<Map<number, number>>(new Map());

  const containerRef = useRef<HTMLDivElement>(null);
  const videoRefs = useRef<Map<number, HTMLVideoElement>>(new Map());
  const observerRef = useRef<IntersectionObserver | null>(null);
  const scrollDebounceRef = useRef<number>(0);
  const progressAnimRef = useRef<number>(0);

  // Persist autoplay preference
  useEffect(() => {
    localStorage.setItem('shorts_autoplay', autoplay ? 'true' : 'false');
  }, [autoplay]);

  // Fetch shorts from API
  const fetchShorts = useCallback(async (offset: number) => {
    try {
      const { data } = await mediaPublicApi.get<ShortsResponse>('/shorts', {
        params: { limit: FETCH_SIZE, offset, sort: 'recent' },
      });
      return data;
    } catch (error) {
      console.error('Failed to fetch shorts:', error);
      return null;
    }
  }, []);

  // Initial load
  useEffect(() => {
    const load = async () => {
      setLoading(true);
      const data = await fetchShorts(0);
      if (data) {
        setShorts(data.shorts);
        setHasMore(data.pagination.hasMore);
      }
      setLoading(false);
    };
    load();
  }, [fetchShorts]);

  // Load more when approaching end
  useEffect(() => {
    if (loadingMore || !hasMore) return;
    if (currentIndex >= shorts.length - PREFETCH_THRESHOLD && shorts.length > 0) {
      setLoadingMore(true);
      fetchShorts(shorts.length).then((data) => {
        if (data && data.shorts.length > 0) {
          setShorts((prev) => [...prev, ...data.shorts]);
          setHasMore(data.pagination.hasMore);
        } else {
          setHasMore(false);
        }
        setLoadingMore(false);
      });
    }
  }, [currentIndex, shorts.length, hasMore, loadingMore, fetchShorts]);

  // Check upvote status for visible shorts
  useEffect(() => {
    if (shorts.length === 0) return;

    const checkUpvoteStatuses = async () => {
      const sessionId = getOrCreateSessionId();
      const indicesToCheck = [currentIndex - 1, currentIndex, currentIndex + 1]
        .filter((i) => i >= 0 && i < shorts.length);

      for (const idx of indicesToCheck) {
        const shortItem = shorts[idx];
        if (!shortItem) continue;
        const shortId = shortItem.id;
        if (upvotedIds.has(shortId)) continue;

        try {
          const { data } = await mediaPublicApi.get(`/public/${shortId}/upvote-status`, {
            params: { sessionId },
          });
          if (data.upvoted) {
            setUpvotedIds((prev) => new Set(prev).add(shortId));
          }
        } catch {
          // Non-critical
        }
      }
    };

    checkUpvoteStatuses();
  }, [currentIndex, shorts]);

  // Auto-close chat when scrolling to different short
  useEffect(() => {
    if (chatVideoId !== null) {
      const currentShort = shorts[currentIndex];
      if (currentShort && currentShort.id !== chatVideoId) {
        setChatVideoId(null);
      }
    }
  }, [currentIndex, chatVideoId, shorts]);

  // Set up IntersectionObserver for scroll-snap detection
  useEffect(() => {
    if (observerRef.current) observerRef.current.disconnect();

    observerRef.current = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
            const idx = parseInt(entry.target.getAttribute('data-index') || '0');
            clearTimeout(scrollDebounceRef.current);
            scrollDebounceRef.current = window.setTimeout(() => {
              setCurrentIndex(idx);
            }, 150);
          }
        }
      },
      {
        root: containerRef.current,
        threshold: 0.5,
      }
    );

    const container = containerRef.current;
    if (container) {
      const items = container.querySelectorAll('[data-short-item]');
      items.forEach((item) => observerRef.current?.observe(item));
    }

    return () => observerRef.current?.disconnect();
  }, [shorts.length]);

  // Video playback management — play current, pause others
  useEffect(() => {
    videoRefs.current.forEach((video, idx) => {
      const distance = Math.abs(idx - currentIndex);
      if (idx === currentIndex) {
        video.muted = muted;
        if (!paused) {
          video.play().catch(() => {});
        }
      } else if (distance <= 1) {
        video.pause();
      } else {
        video.pause();
        if (distance > 3) {
          video.removeAttribute('src');
          video.load();
        }
      }
    });
  }, [currentIndex, muted, paused]);

  // Progress bar animation for current video
  useEffect(() => {
    const updateProgress = () => {
      const video = videoRefs.current.get(currentIndex);
      if (video && video.duration) {
        setProgress((video.currentTime / video.duration) * 100);
      }
      progressAnimRef.current = requestAnimationFrame(updateProgress);
    };
    progressAnimRef.current = requestAnimationFrame(updateProgress);
    return () => cancelAnimationFrame(progressAnimRef.current);
  }, [currentIndex]);

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;

      switch (e.key) {
        case 'ArrowDown':
        case 'j':
          e.preventDefault();
          scrollToIndex(Math.min(currentIndex + 1, shorts.length - 1));
          break;
        case 'ArrowUp':
        case 'k':
          e.preventDefault();
          scrollToIndex(Math.max(currentIndex - 1, 0));
          break;
        case ' ':
          e.preventDefault();
          setPaused((p) => !p);
          break;
        case 'm':
        case 'M':
          e.preventDefault();
          setMuted((m) => !m);
          break;
        case 'f':
        case 'F':
          e.preventDefault();
          setIsFullscreen((f) => !f);
          break;
        case 'h':
        case 'H':
          e.preventDefault();
          setActionsCollapsed((c) => !c);
          break;
        case 'z':
        case 'Z':
          e.preventDefault();
          setIsZoomed((z) => !z);
          break;
        case 'Escape':
          if (chatVideoId !== null) {
            setChatVideoId(null);
          } else if (shareVideoId !== null) {
            setShareVideoId(null);
          } else if (isFullscreen) {
            setIsFullscreen(false);
          } else {
            navigate('/gallery');
          }
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [currentIndex, shorts.length, navigate, chatVideoId, shareVideoId, isFullscreen]);

  // Listen for browser fullscreen exit (e.g. pressing Esc in native fullscreen)
  useEffect(() => {
    const handleFsChange = () => {
      if (!document.fullscreenElement) {
        setIsFullscreen(false);
      }
    };
    document.addEventListener('fullscreenchange', handleFsChange);
    return () => document.removeEventListener('fullscreenchange', handleFsChange);
  }, []);

  const scrollToIndex = (index: number) => {
    const container = containerRef.current;
    if (!container) return;
    const items = container.querySelectorAll('[data-short-item]');
    if (items[index]) {
      items[index].scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  };

  const handleVideoRef = (index: number, el: HTMLVideoElement | null) => {
    if (el) {
      videoRefs.current.set(index, el);
    } else {
      videoRefs.current.delete(index);
    }
  };

  const handleTogglePlay = () => {
    setPaused((p) => {
      const video = videoRefs.current.get(currentIndex);
      if (video) {
        if (p) {
          video.play().catch(() => {});
        } else {
          video.pause();
        }
      }
      return !p;
    });
  };

  // Autoplay: advance to next video when current one ends
  const handleVideoEnded = useCallback(() => {
    if (autoplay && currentIndex < shorts.length - 1) {
      scrollToIndex(currentIndex + 1);
    }
  }, [autoplay, currentIndex, shorts.length]);

  // Fullscreen toggle using Fullscreen API
  const handleToggleFullscreen = useCallback(() => {
    const container = containerRef.current;
    if (!container) return;

    if (!isFullscreen) {
      const rfs = container.requestFullscreen
        || (container as any).webkitRequestFullscreen;
      if (rfs) rfs.call(container);
      setIsFullscreen(true);
    } else {
      const efs = document.exitFullscreen
        || (document as any).webkitExitFullscreen;
      if (efs && document.fullscreenElement) efs.call(document);
      setIsFullscreen(false);
    }
  }, [isFullscreen]);

  // Upvote handler
  const handleUpvote = async (short: ShortVideo) => {
    if (upvotingId !== null) return;

    try {
      setUpvotingId(short.id);
      const sessionId = getOrCreateSessionId();
      const { data } = await mediaPublicApi.post(`/public/${short.id}/upvote`, { sessionId });

      if (data.upvoted) {
        setUpvotedIds((prev) => new Set(prev).add(short.id));
        setUpvoteCountOverrides((prev) => {
          const m = new Map(prev);
          m.set(short.id, (prev.get(short.id) ?? short.upvoteCount) + 1);
          return m;
        });
      } else {
        setUpvotedIds((prev) => {
          const s = new Set(prev);
          s.delete(short.id);
          return s;
        });
        setUpvoteCountOverrides((prev) => {
          const m = new Map(prev);
          m.set(short.id, (prev.get(short.id) ?? short.upvoteCount) - 1);
          return m;
        });
      }

      message.success(data.upvoted ? 'Upvoted!' : 'Upvote removed');
    } catch (error: unknown) {
      if (axios.isAxiosError(error) && error.response?.status === 401) {
        message.info('Log in to upvote');
      } else {
        message.error('Failed to upvote');
      }
    } finally {
      setUpvotingId(null);
    }
  };

  // Share helpers
  const getShareUrl = (short: ShortVideo) =>
    `${window.location.origin}/gallery/watch/${short.id}`;

  const getShareTitle = (short: ShortVideo) =>
    short.title || 'Check out this video';

  const handleCopyLink = async (short: ShortVideo) => {
    try {
      await navigator.clipboard.writeText(getShareUrl(short));
      message.success('Link copied!');
    } catch {
      message.error('Failed to copy link');
    }
  };

  const handleNativeShare = async (short: ShortVideo) => {
    try {
      await navigator.share({
        title: getShareTitle(short),
        url: getShareUrl(short),
      });
    } catch {
      // User cancelled or error — ignore
    }
  };

  const formatDuration = (seconds: number | null) => {
    if (!seconds) return '';
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };

  const formatCount = (count: number) => {
    if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M`;
    if (count >= 1000) return `${(count / 1000).toFixed(1)}K`;
    return count.toString();
  };

  // Determine orientation label from dimensions
  const getOrientationLabel = (short: ShortVideo): string | null => {
    if (short.orientation === 'vertical' || (short.width && short.height && short.height > short.width)) return 'V';
    if (short.orientation === 'horizontal' || (short.width && short.height && short.width > short.height)) return 'H';
    if (short.orientation === 'square') return 'S';
    return null;
  };

  if (loading) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '80vh' }}>
        <Spin size="large" />
      </div>
    );
  }

  if (shorts.length === 0) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '80vh' }}>
        <Empty
          description="No shorts available yet"
          image={Empty.PRESENTED_IMAGE_SIMPLE}
        />
      </div>
    );
  }

  const containerHeight = isFullscreen ? '100vh' : isMobile ? 'calc(100vh - 48px)' : 'calc(100vh - 24px)';
  const videoMaxWidth = isMobile ? '100%' : 480;

  const shareShort = shareVideoId !== null ? shorts.find((s) => s.id === shareVideoId) : null;

  return (
    <div
      ref={containerRef}
      style={{
        height: containerHeight,
        overflowY: 'auto',
        scrollSnapType: 'y mandatory',
        scrollBehavior: 'smooth',
        position: 'relative',
        margin: isFullscreen ? 0 : isMobile ? '-8px' : '-12px',
        WebkitOverflowScrolling: 'touch',
        background: '#000',
      }}
    >
      {/* Prefetch links for next videos.
          When HLS is ready, prefetching the master manifest (~1 KB) warms the
          browser cache so swiping forward starts playback in <100ms. For
          MP4-only shorts we keep the original prefetch of the stream URL. */}
      {shorts.slice(currentIndex + 1, currentIndex + 3).map((s) => {
        if (!s.videoUrl) return null;
        if (s.hlsStatus === 'READY') {
          return (
            <link
              key={`prefetch-hls-${s.id}`}
              rel="prefetch"
              as="fetch"
              href={`/media/public/${s.id}/hls/master.m3u8`}
              crossOrigin="anonymous"
            />
          );
        }
        return <link key={`prefetch-${s.id}`} rel="prefetch" href={`/media/public/${s.id}/stream`} />;
      })}

      {shorts.map((short, index) => {
        const distance = Math.abs(index - currentIndex);
        const isActive = index === currentIndex;
        const isNear = distance <= 1;
        const isMedium = distance <= 3;
        const isUpvoted = upvotedIds.has(short.id);
        const displayUpvoteCount = upvoteCountOverrides.get(short.id) ?? short.upvoteCount;
        const displayCommentCount = commentCountOverrides.get(short.id) ?? short.commentCount;
        const orientationLabel = getOrientationLabel(short);

        return (
          <div
            key={short.id}
            data-short-item
            data-index={index}
            style={{
              height: containerHeight,
              scrollSnapAlign: 'start',
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              position: 'relative',
              background: '#000',
            }}
          >
            {/* Video container */}
            <div
              style={{
                position: 'relative',
                width: isFullscreen ? '100%' : videoMaxWidth,
                maxWidth: '100%',
                height: '100%',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
              }}
            >
              {/* Progress bar at top */}
              {isActive && (
                <div
                  style={{
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    right: 0,
                    height: 3,
                    background: 'rgba(255,255,255,0.2)',
                    zIndex: 20,
                  }}
                >
                  <div
                    style={{
                      height: '100%',
                      width: `${progress}%`,
                      background: token.colorPrimary,
                      transition: 'width 0.1s linear',
                    }}
                  />
                </div>
              )}

              {/* Orientation badge (top-right) */}
              {isActive && !isFullscreen && orientationLabel && (
                <div
                  style={{
                    position: 'absolute',
                    top: 12,
                    right: isMobile ? 8 : 16,
                    background: 'rgba(0,0,0,0.5)',
                    backdropFilter: 'blur(8px)',
                    color: '#fff',
                    fontSize: 11,
                    fontWeight: 700,
                    padding: '3px 8px',
                    borderRadius: 6,
                    zIndex: 20,
                    letterSpacing: 0.5,
                  }}
                >
                  {orientationLabel}
                </div>
              )}

              {/* Render tier: Full (active + adjacent), Simplified (medium), Placeholder (far) */}
              {isNear ? (
                <HlsAwareShortVideo
                  short={short}
                  isActive={isActive}
                  onRefChange={(el) => handleVideoRef(index, el)}
                  loop={!autoplay}
                  muted={muted}
                  isZoomed={isZoomed}
                  onClick={handleTogglePlay}
                  onEnded={isActive ? handleVideoEnded : undefined}
                />
              ) : isMedium ? (
                <img
                  src={short.thumbnailPath ? `/media/public/${short.id}/thumbnail` : undefined}
                  alt={short.title || short.filename}
                  style={{
                    width: '100%',
                    height: '100%',
                    objectFit: 'contain',
                    background: '#000',
                  }}
                />
              ) : (
                <div
                  style={{
                    width: '100%',
                    height: '100%',
                    background: '#111',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                  }}
                >
                  <PlayCircleOutlined style={{ fontSize: 48, color: 'rgba(255,255,255,0.2)' }} />
                </div>
              )}

              {/* Paused overlay */}
              {isActive && paused && (
                <div
                  onClick={handleTogglePlay}
                  style={{
                    position: 'absolute',
                    inset: 0,
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    cursor: 'pointer',
                    zIndex: 15,
                  }}
                >
                  <PlayCircleOutlined
                    style={{
                      fontSize: 72,
                      color: 'rgba(255,255,255,0.8)',
                      filter: 'drop-shadow(0 2px 8px rgba(0,0,0,0.5))',
                    }}
                  />
                </div>
              )}

              {/* Right action bar — collapsed state: small expand pill */}
              {(isActive || isNear) && actionsCollapsed && (
                <div
                  onClick={() => setActionsCollapsed(false)}
                  style={{
                    position: 'absolute',
                    right: isMobile ? 4 : 8,
                    bottom: isMobile ? 120 : 140,
                    width: 28,
                    height: 28,
                    borderRadius: '50%',
                    background: 'rgba(255,255,255,0.15)',
                    backdropFilter: 'blur(8px)',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    cursor: 'pointer',
                    zIndex: 10,
                    transition: 'background 0.2s',
                    color: 'rgba(255,255,255,0.6)',
                    fontSize: 14,
                  }}
                  title="Show controls (H)"
                >
                  <MenuOutlined />
                </div>
              )}

              {/* Right action bar — expanded state */}
              {(isActive || isNear) && !actionsCollapsed && (
                <div
                  style={{
                    position: 'absolute',
                    right: isMobile ? 8 : 16,
                    bottom: isMobile ? 120 : 140,
                    display: 'flex',
                    flexDirection: 'column',
                    alignItems: 'center',
                    gap: 16,
                    zIndex: 10,
                  }}
                >
                  {/* Upvote */}
                  <ActionButton
                    icon={isUpvoted ? <LikeFilled style={{ color: token.colorPrimary }} /> : <LikeOutlined />}
                    count={formatCount(displayUpvoteCount)}
                    onClick={() => handleUpvote(short)}
                    active={isUpvoted}
                  />

                  {/* Comments */}
                  <ActionButton
                    icon={<CommentOutlined />}
                    count={formatCount(displayCommentCount)}
                    onClick={() => setChatVideoId(short.id)}
                    active={chatVideoId === short.id}
                  />

                  {/* Views */}
                  <ActionButton
                    icon={<EyeOutlined />}
                    count={formatCount(short.viewCount)}
                  />

                  {/* Share */}
                  <ActionButton
                    icon={<ShareAltOutlined />}
                    onClick={() => setShareVideoId(short.id)}
                  />

                  {/* Zoom toggle */}
                  <ActionButton
                    icon={isZoomed ? <ZoomOutOutlined /> : <ZoomInOutlined />}
                    onClick={() => setIsZoomed((z) => !z)}
                    title={isZoomed ? 'Fit (Z)' : 'Zoom (Z)'}
                  />

                  {/* Fullscreen toggle */}
                  <ActionButton
                    icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
                    onClick={handleToggleFullscreen}
                    title={isFullscreen ? 'Exit fullscreen (F)' : 'Fullscreen (F)'}
                  />

                  {/* Autoplay toggle */}
                  <ActionButton
                    icon={autoplay ? <CaretRightOutlined /> : <RetweetOutlined />}
                    onClick={() => setAutoplay((a) => !a)}
                    active={autoplay}
                    title={autoplay ? 'Autoplay on' : 'Loop on'}
                  />

                  {/* Mute toggle */}
                  <ActionButton
                    icon={muted ? <MutedOutlined /> : <SoundOutlined />}
                    onClick={() => setMuted((m) => !m)}
                  />

                  {/* Collapse action bar */}
                  <ActionButton
                    icon={<CloseOutlined style={{ fontSize: 14 }} />}
                    onClick={() => setActionsCollapsed(true)}
                    title="Hide controls (H)"
                    small
                  />
                </div>
              )}

              {/* Bottom info overlay — hidden in fullscreen */}
              {(isActive || isNear) && !isFullscreen && (
                <div
                  style={{
                    position: 'absolute',
                    bottom: 0,
                    left: 0,
                    right: actionsCollapsed ? 12 : isMobile ? 60 : 80,
                    padding: isMobile ? '16px 12px' : '20px 16px',
                    background: 'linear-gradient(transparent, rgba(0,0,0,0.8))',
                    zIndex: 10,
                  }}
                >
                  <div
                    style={{
                      color: '#fff',
                      fontSize: isMobile ? 14 : 16,
                      fontWeight: 600,
                      marginBottom: 6,
                      textShadow: '0 1px 3px rgba(0,0,0,0.5)',
                      overflow: 'hidden',
                      display: '-webkit-box',
                      WebkitLineClamp: 2,
                      WebkitBoxOrient: 'vertical',
                    }}
                  >
                    {short.title || short.filename}
                  </div>
                  <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                    {short.durationSeconds && (
                      <span
                        style={{
                          background: 'rgba(255,255,255,0.15)',
                          color: '#fff',
                          padding: '2px 8px',
                          borderRadius: 4,
                          fontSize: 11,
                        }}
                      >
                        {formatDuration(short.durationSeconds)}
                      </span>
                    )}
                    {short.quality && (
                      <span
                        style={{
                          background: 'rgba(255,255,255,0.15)',
                          color: '#fff',
                          padding: '2px 8px',
                          borderRadius: 4,
                          fontSize: 11,
                        }}
                      >
                        {short.quality}
                      </span>
                    )}
                    <span
                      style={{
                        color: 'rgba(255,255,255,0.6)',
                        fontSize: 11,
                        display: 'flex',
                        alignItems: 'center',
                        gap: 4,
                      }}
                    >
                      {formatCount(short.viewCount)} views
                    </span>
                  </div>
                </div>
              )}

              {/* Chat bottom sheet */}
              {isActive && chatVideoId === short.id && (
                <ChatBottomSheet
                  videoId={short.id}
                  isMobile={isMobile}
                  onClose={() => setChatVideoId(null)}
                  onCommentPosted={() => {
                    setCommentCountOverrides((prev) => {
                      const m = new Map(prev);
                      m.set(short.id, (prev.get(short.id) ?? short.commentCount) + 1);
                      return m;
                    });
                  }}
                />
              )}
            </div>
          </div>
        );
      })}

      {/* Loading more indicator */}
      {loadingMore && (
        <div
          style={{
            height: 80,
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <Spin />
        </div>
      )}

      {/* Navigation hints (desktop only, hidden in fullscreen) */}
      {!isMobile && !isFullscreen && shorts.length > 1 && (
        <div
          style={{
            position: 'fixed',
            right: 24,
            top: '50%',
            transform: 'translateY(-50%)',
            display: 'flex',
            flexDirection: 'column',
            gap: 8,
            zIndex: 100,
          }}
        >
          <Button
            type="text"
            icon={<ArrowUpOutlined />}
            disabled={currentIndex === 0}
            onClick={() => scrollToIndex(currentIndex - 1)}
            style={{
              color: 'rgba(255,255,255,0.6)',
              background: 'rgba(0,0,0,0.3)',
              border: 'none',
              borderRadius: '50%',
              width: 40,
              height: 40,
            }}
          />
          <div
            style={{
              color: 'rgba(255,255,255,0.5)',
              fontSize: 12,
              textAlign: 'center',
            }}
          >
            {currentIndex + 1}/{shorts.length}
          </div>
          <Button
            type="text"
            icon={<ArrowDownOutlined />}
            disabled={currentIndex >= shorts.length - 1}
            onClick={() => scrollToIndex(currentIndex + 1)}
            style={{
              color: 'rgba(255,255,255,0.6)',
              background: 'rgba(0,0,0,0.3)',
              border: 'none',
              borderRadius: '50%',
              width: 40,
              height: 40,
            }}
          />
        </div>
      )}

      {/* Share Modal */}
      <Modal
        open={shareVideoId !== null}
        onCancel={() => setShareVideoId(null)}
        footer={null}
        title={null}
        closable
        centered
        width={isMobile ? '100%' : 400}
        styles={{
          content: {
            background: '#1a1a1a',
            borderRadius: 16,
            padding: 0,
          },
          mask: { background: 'rgba(0,0,0,0.7)' },
        }}
      >
        {shareShort && (
          <div style={{ padding: 24 }}>
            <div style={{ color: '#fff', fontSize: 18, fontWeight: 600, marginBottom: 20, textAlign: 'center' }}>
              Share
            </div>

            {/* Copy Link */}
            <Button
              block
              size="large"
              icon={<CopyOutlined />}
              onClick={() => handleCopyLink(shareShort)}
              style={{
                marginBottom: 16,
                background: '#333',
                borderColor: '#444',
                color: '#fff',
                height: 48,
                borderRadius: 10,
              }}
            >
              Copy Link
            </Button>

            {/* Social Platform Grid */}
            <div
              style={{
                display: 'grid',
                gridTemplateColumns: isMobile ? '1fr 1fr' : '1fr 1fr 1fr',
                gap: 10,
                marginBottom: 16,
              }}
            >
              {SHARE_PLATFORMS.map((platform) => (
                <Button
                  key={platform.key}
                  block
                  onClick={() => {
                    const url = platform.getUrl(getShareUrl(shareShort), getShareTitle(shareShort));
                    if (platform.key === 'email') {
                      window.location.href = url;
                    } else {
                      window.open(url, '_blank', 'noopener,noreferrer');
                    }
                  }}
                  icon={platform.key === 'email' ? <MailOutlined /> : <LinkOutlined />}
                  style={{
                    background: platform.color,
                    borderColor: platform.color,
                    color: '#fff',
                    height: 44,
                    borderRadius: 10,
                    fontSize: 13,
                    fontWeight: 500,
                  }}
                >
                  {platform.label}
                </Button>
              ))}
            </div>

            {/* Native Share (mobile only) */}
            {typeof navigator.share === 'function' && (
              <Button
                block
                size="large"
                icon={<ShareAltOutlined />}
                onClick={() => handleNativeShare(shareShort)}
                type="primary"
                style={{
                  height: 48,
                  borderRadius: 10,
                }}
              >
                More Options...
              </Button>
            )}
          </div>
        )}
      </Modal>
    </div>
  );
}

/** Chat bottom sheet overlay */
function ChatBottomSheet({
  videoId,
  isMobile,
  onClose,
  onCommentPosted,
}: {
  videoId: number;
  isMobile: boolean;
  onClose: () => void;
  onCommentPosted: () => void;
}) {
  const navigate = useNavigate();
  const sheetHeight = isMobile ? '60%' : '50%';

  // Listen to SSE for real-time comment count updates
  useEffect(() => {
    const sseUrl = `/media/public/${videoId}/chat-stream`;
    const eventSource = new EventSource(sseUrl);

    eventSource.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        if (data.type === 'new_comment') {
          onCommentPosted();
        }
      } catch {
        // ignore
      }
    };

    return () => eventSource.close();
  }, [videoId, onCommentPosted]);

  return (
    <>
      {/* Backdrop */}
      <div
        onClick={onClose}
        style={{
          position: 'absolute',
          inset: 0,
          background: 'rgba(0,0,0,0.4)',
          zIndex: 30,
        }}
      />

      {/* Sheet */}
      <div
        style={{
          position: 'absolute',
          bottom: 0,
          left: 0,
          right: 0,
          height: sheetHeight,
          background: '#1a1a1a',
          borderTopLeftRadius: 16,
          borderTopRightRadius: 16,
          zIndex: 31,
          display: 'flex',
          flexDirection: 'column',
          overflow: 'hidden',
          animation: 'slideUp 0.25s ease-out',
        }}
      >
        {/* Drag handle + close */}
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            padding: '8px 12px 0',
            flexShrink: 0,
          }}
        >
          <div style={{ width: 32 }} />
          <div
            style={{
              width: 36,
              height: 4,
              borderRadius: 2,
              background: 'rgba(255,255,255,0.3)',
            }}
          />
          <Button
            type="text"
            icon={<CloseOutlined />}
            onClick={onClose}
            size="small"
            style={{ color: 'rgba(255,255,255,0.7)' }}
          />
        </div>

        {/* LiveChat */}
        <div style={{ flex: 1, overflow: 'hidden' }}>
          <MediaAuthProvider>
            <LiveChat
              videoId={videoId}
              isOpen={true}
              onRequestLogin={() => navigate('/login')}
            />
          </MediaAuthProvider>
        </div>
      </div>

      {/* Slide-up animation */}
      <style>{`
        @keyframes slideUp {
          from { transform: translateY(100%); }
          to { transform: translateY(0); }
        }
      `}</style>
    </>
  );
}

/** Floating action button for the right sidebar */
function ActionButton({
  icon,
  count,
  onClick,
  active,
  title,
  small,
}: {
  icon: React.ReactNode;
  count?: string;
  onClick?: () => void;
  active?: boolean;
  title?: string;
  small?: boolean;
}) {
  const size = small ? 32 : 44;
  const fontSize = small ? 14 : 20;

  return (
    <div
      onClick={onClick}
      title={title}
      style={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        cursor: onClick ? 'pointer' : 'default',
      }}
    >
      <div
        style={{
          width: size,
          height: size,
          borderRadius: '50%',
          background: active ? 'rgba(255,255,255,0.25)' : 'rgba(255,255,255,0.1)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize,
          color: '#fff',
          backdropFilter: 'blur(8px)',
          transition: 'background 0.2s, transform 0.1s',
        }}
        onMouseEnter={(e) => { e.currentTarget.style.background = 'rgba(255,255,255,0.2)'; }}
        onMouseLeave={(e) => { e.currentTarget.style.background = active ? 'rgba(255,255,255,0.25)' : 'rgba(255,255,255,0.1)'; }}
        onMouseDown={(e) => { e.currentTarget.style.transform = 'scale(0.92)'; }}
        onMouseUp={(e) => { e.currentTarget.style.transform = 'scale(1)'; }}
      >
        {icon}
      </div>
      {count !== undefined && (
        <span style={{ color: '#fff', fontSize: 11, marginTop: 4, textShadow: '0 1px 2px rgba(0,0,0,0.5)' }}>
          {count}
        </span>
      )}
    </div>
  );
}

// HLS-aware video element for the shorts feed. Uses HLS when the short has
// hlsStatus='READY', otherwise falls back to the MP4 stream URL. Owns its
// own ref so useHls can attach hls.js cleanly, and forwards the underlying
// HTMLVideoElement to the parent's videoRefs Map via onRefChange.
interface HlsAwareShortVideoProps {
  short: ShortVideo;
  isActive: boolean;
  onRefChange: (el: HTMLVideoElement | null) => void;
  loop: boolean;
  muted: boolean;
  isZoomed: boolean;
  onClick: () => void;
  onEnded?: () => void;
}

function HlsAwareShortVideo({
  short,
  isActive,
  onRefChange,
  loop,
  muted,
  isZoomed,
  onClick,
  onEnded,
}: HlsAwareShortVideoProps) {
  const videoRef = useRef<HTMLVideoElement>(null);
  const hlsManifestUrl = short.hlsStatus === 'READY'
    ? `/api/public/${short.id}/hls/master.m3u8`
    : null;
  const { error: hlsError } = useHls(videoRef, hlsManifestUrl);
  const useMp4Src = !hlsManifestUrl || !!hlsError;

  // Register/deregister with the parent's refs Map.
  useEffect(() => {
    onRefChange(videoRef.current);
    return () => onRefChange(null);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <video
      ref={videoRef}
      src={useMp4Src ? `/media/public/${short.id}/stream` : undefined}
      poster={short.thumbnailPath ? `/media/public/${short.id}/thumbnail` : undefined}
      loop={loop}
      playsInline
      muted={muted}
      preload={isActive ? 'auto' : 'metadata'}
      onClick={onClick}
      onEnded={onEnded}
      style={{
        width: '100%',
        height: '100%',
        objectFit: isZoomed ? 'cover' : 'contain',
        cursor: 'pointer',
        background: '#000',
      }}
    />
  );
}

