import React, { useState, useEffect } from 'react';
import { 
  ChevronLeft, 
  ChevronRight, 
  X, 
  MoreHorizontal, 
  Heart, 
  MessageCircle, 
  Play, 
  Bookmark 
} from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react';
import { Post } from '../types';
import { cn, formatDateSafe } from '../lib/utils';
import { FADE, NAVIGATE, PRESENT, prefersReducedMotion, withVelocity } from '../lib/motion';
import { MediaRenderer } from './MediaRenderer';

interface PostModalProps {
  post: Post;
  nextPost?: Post;
  prevPost?: Post;
  onClose: () => void;
  onNextPost?: () => void;
  onPrevPost?: () => void;
  hasNextPost?: boolean;
  hasPrevPost?: boolean;
  profilePic: string | null;
}

export const PostModal: React.FC<PostModalProps> = ({ 
  post, nextPost, prevPost, onClose, onNextPost, onPrevPost, hasNextPost, hasPrevPost, profilePic
}) => {
  const [currentIndex, setCurrentIndex] = useState(0);
  /**
   * How the next slide/post should enter: along which axis, in which direction,
   * and carrying how much velocity from the gesture that triggered it.
   */
  const [slideMotion, setSlideMotion] = useState<{ axis: 'x' | 'y'; dir: number; velocity: number }>(
    { axis: 'x', dir: 0, velocity: 0 },
  );
  const reduceMotion = prefersReducedMotion();

  // Preloading Logic
  useEffect(() => {
    const controller = new AbortController();
    
    const preloadMedia = async (url: string, type: 'image' | 'video') => {
      if (!url) return;
      try {
        if (type === 'image') {
          const img = new Image();
          img.src = url;
        } else {
          const video = document.createElement('video');
          video.src = url;
          video.preload = 'auto';
        }
      } catch (e) {}
    };

    // 1. Current post: Immediate preload of first two slides
    if (post.media[0]) preloadMedia(post.media[0].url, post.media[0].type);
    if (post.media[1]) preloadMedia(post.media[1].url, post.media[1].type);

    // 2. Next/Prev posts: Preload their first slides
    if (nextPost?.media[0]) preloadMedia(nextPost.media[0].url, nextPost.media[0].type);
    if (prevPost?.media[0]) preloadMedia(prevPost.media[0].url, prevPost.media[0].type);

    // 3. Current post: Delayed preload of the rest
    const timeout = setTimeout(() => {
      for (let i = 2; i < post.media.length; i++) {
        if (controller.signal.aborted) break;
        preloadMedia(post.media[i].url, post.media[i].type);
      }
    }, 1000);

    return () => {
      controller.abort();
      clearTimeout(timeout);
    };
  }, [post.id, post.media, nextPost?.id, prevPost?.id]);

  useEffect(() => setCurrentIndex(0), [post.id]);
  useEffect(() => {
    // Arrows page within the carousel — the thing the arrows visually point at.
    // Moving between posts stays on the side buttons, with , and . as keyboard
    // equivalents.
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'ArrowRight') paginate(1);
      else if (e.key === 'ArrowLeft') paginate(-1);
      else if (e.key === '.') goToPost(1, 'x');
      else if (e.key === ',') goToPost(-1, 'x');
      else if (e.key === 'Escape') onClose();
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [onNextPost, onPrevPost, currentIndex, post.media.length, onClose]);

  const paginate = (newDirection: number, velocity = 0) => {
    const nextIndex = currentIndex + newDirection;
    if (nextIndex >= 0 && nextIndex < post.media.length) {
      setSlideMotion({ axis: 'x', dir: newDirection, velocity });
      setCurrentIndex(nextIndex);
    }
  };

  /**
   * Move between posts, animating along the axis the input implies: vertical
   * for a touch swipe, horizontal for the desktop arrows and arrow keys.
   */
  const goToPost = (dir: 1 | -1, axis: 'x' | 'y', velocity = 0) => {
    if (dir > 0 ? !hasNextPost : !hasPrevPost) return;
    setSlideMotion({ axis, dir, velocity });
    if (dir > 0) onNextPost?.(); else onPrevPost?.();
  };

  type SlideMotion = { axis: 'x' | 'y'; dir: number };
  const offscreen = (dir: number) => (dir > 0 ? '100%' : '-100%');
  const variants = {
    enter: ({ axis, dir }: SlideMotion) =>
      axis === 'y'
        ? { y: offscreen(dir), x: 0, opacity: 1, zIndex: 0 }
        : { x: offscreen(dir), y: 0, opacity: 1, zIndex: 0 },
    center: { zIndex: 1, x: 0, y: 0, opacity: 1 },
    exit: ({ axis, dir }: SlideMotion) =>
      axis === 'y'
        ? { zIndex: 0, y: offscreen(-dir), x: 0, opacity: 1 }
        : { zIndex: 0, x: offscreen(-dir), y: 0, opacity: 1 },
  };
  const swipePower = (offset: number, velocity: number) => Math.abs(offset) * velocity;

  /**
   * Desktop-only surface: mobile opens PostFeed instead, so the only vertical
   * gesture left here is drag-to-dismiss.
   */
  const handleVerticalDragEnd = (offset: { y: number }, velocity: { y: number }) => {
    if (offset.y > 200 || velocity.y > 800) onClose();
  };

  /*
   * Horizontal padding on the overlay reserves a gutter for the prev/next
   * arrows so they always sit *outside* the modal. Without it the modal grows
   * until it sits under them and a white chevron lands on the white caption
   * panel, leaving the control invisible until hovered.
   *
   * overscroll-contain stops wheel events chaining through to the very long
   * post grid behind the overlay.
   */
  return (
    <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={FADE} className="fixed inset-0 z-50 flex items-start justify-center bg-[#0c1014]/95 md:bg-[#0c1014]/70 p-0 md:py-10 md:px-16 lg:px-24 overflow-y-auto overscroll-contain text-black" onClick={onClose}>
      <div className="min-h-full w-full flex items-center justify-center md:py-0">
        <button onClick={onClose} className="fixed top-4 right-4 text-white hover:text-gray-300 z-50 p-2 md:p-3 bg-black/20 rounded-full backdrop-blur-sm"><X size={24} className="md:w-8 md:h-8" /></button>
        {/* Solid pill so the arrows read against whatever sits behind them. */}
        {hasPrevPost && onPrevPost && <button aria-label="Previous post" onClick={(e) => { e.stopPropagation(); goToPost(-1, 'x'); }} className="hidden md:flex items-center justify-center fixed md:left-3 lg:left-6 top-1/2 -translate-y-1/2 z-50 p-2 rounded-full bg-white/90 hover:bg-white text-gray-800 shadow-lg transition-transform hover:scale-110 active:scale-90"><ChevronLeft size={28} strokeWidth={2} /></button>}
        {hasNextPost && onNextPost && <button aria-label="Next post" onClick={(e) => { e.stopPropagation(); goToPost(1, 'x'); }} className="hidden md:flex items-center justify-center fixed md:right-3 lg:right-6 top-1/2 -translate-y-1/2 z-50 p-2 rounded-full bg-white/90 hover:bg-white text-gray-800 shadow-lg transition-transform hover:scale-110 active:scale-90"><ChevronRight size={28} strokeWidth={2} /></button>}
        <motion.div drag="y" dragDirectionLock dragConstraints={{ top: 0, bottom: 0 }} dragElastic={0.15} onDragEnd={(e, { offset, velocity }) => handleVerticalDragEnd(offset, velocity)} initial={reduceMotion ? false : { opacity: 0, scale: 0.96 }} animate={{ opacity: 1, scale: 1 }} exit={reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.96 }} transition={PRESENT} className="bg-black flex flex-col md:flex-row w-full max-w-6xl h-auto md:rounded-sm overflow-hidden shadow-2xl relative text-black" onClick={e => e.stopPropagation()}>
          <div className="relative bg-black flex items-center justify-center group overflow-hidden w-full h-auto text-black">
            <div className="w-full grid grid-cols-1 grid-rows-1 text-black">
              <AnimatePresence initial={false} custom={slideMotion}>
                <motion.div
                  key={`${post.id}-${currentIndex}`}
                  custom={slideMotion}
                  variants={variants}
                  initial="enter"
                  animate="center"
                  exit="exit"
                  transition={reduceMotion
                    ? { duration: 0 }
                    : { x: withVelocity(slideMotion.velocity, NAVIGATE), y: withVelocity(slideMotion.velocity, NAVIGATE) }}
                  
                  drag="x" 
                  dragDirectionLock 
                  dragConstraints={{ left: 0, right: 0 }} 
                  dragElastic={0.5} 
                  onDragEnd={(e, { offset, velocity }) => {
                    // Carousel only. Crossing into the next post from the last
                    // slide made a horizontal flick mean two different things.
                    const s = swipePower(offset.x, velocity.x);
                    if (s < -15000) paginate(1, velocity.x);
                    else if (s > 15000) paginate(-1, velocity.x);
                  }} 
                  className="col-start-1 row-start-1 w-full flex items-center justify-center cursor-grab active:cursor-grabbing relative text-black"
                >
                  <MediaRenderer file={post.media[currentIndex]} isFullView={true} />
                </motion.div>
              </AnimatePresence>
            </div>
            {post.media.length > 1 && (
              <>
                {currentIndex > 0 && <button onClick={(e) => { e.stopPropagation(); paginate(-1); }} className="hidden md:block absolute left-4 top-1/2 -translate-y-1/2 bg-white/20 hover:bg-white/40 text-white p-2 rounded-full backdrop-blur-md transition-all opacity-0 group-hover:opacity-100 z-30"><ChevronLeft size={24} /></button>}
                {currentIndex < post.media.length - 1 && <button onClick={(e) => { e.stopPropagation(); paginate(1); }} className="hidden md:block absolute right-4 top-1/2 -translate-y-1/2 bg-white/20 hover:bg-white/40 text-white p-2 rounded-full backdrop-blur-md transition-all opacity-0 group-hover:opacity-100 z-30"><ChevronRight size={24} /></button>}
                <div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-30 text-black">{post.media.map((_, i) => <div key={i} className={cn("w-1.5 h-1.5 rounded-full transition-all", i === currentIndex ? "bg-blue-500 scale-125" : "bg-white/40 shadow-sm")} />)}</div>
              </>
            )}
          </div>
          <div className="w-full md:w-80 lg:w-96 bg-white flex flex-col border-l border-gray-200 overflow-hidden shrink-0 text-black">
            <div className="p-3 md:p-4 border-b border-gray-100 flex items-center justify-between shrink-0 text-black">
              <div className="flex items-center gap-3 text-black">
                <div className="w-8 h-8 rounded-full bg-gradient-to-tr from-yellow-400 to-purple-600 p-0.5 text-black"><div className="w-full h-full rounded-full bg-white p-0.5 text-black"><div className="w-full h-full rounded-full bg-gray-200 flex items-center justify-center overflow-hidden text-[10px] font-bold uppercase text-black">{profilePic ? <img src={profilePic} alt="" className="w-full h-full object-cover text-black" referrerPolicy="no-referrer" /> : <span className="text-black">{post.username[0]}</span>}</div></div></div>
                <span className="font-semibold text-sm text-black">{post.username}</span>
              </div>
              <MoreHorizontal size={20} className="text-gray-500 text-black" />
            </div>
            <div className="flex-1 overflow-y-auto p-3 md:p-4 space-y-4 min-h-0 md:max-h-[60vh] text-black">
              <div className="flex gap-3 text-black">
                <div className="w-8 h-8 rounded-full bg-gray-200 flex-shrink-0 flex items-center justify-center text-[10px] font-bold uppercase overflow-hidden text-black">{profilePic ? <img src={profilePic} alt="" className="w-full h-full object-cover" referrerPolicy="no-referrer" /> : <span className="text-black">{post.username[0]}</span>}</div>
                <div className="text-sm text-black"><span className="font-semibold mr-2 text-black">{post.username}</span><span className="whitespace-pre-wrap text-black">{post.caption}</span><div className="mt-2 text-xs text-gray-500 uppercase tracking-tight text-black">{formatDateSafe(post.date, 'MMMM d, yyyy')}</div></div>
              </div>
            </div>
            <div className="p-3 md:p-4 border-t border-gray-100 space-y-3 shrink-0 bg-white text-black">
              <div className="flex items-center justify-between text-black"><div className="flex items-center gap-4 text-black"><Heart size={24} className="hover:text-gray-500 cursor-pointer text-black" /><MessageCircle size={24} className="hover:text-gray-500 cursor-pointer text-black" /><Play size={24} className="hover:text-gray-500 cursor-pointer text-black" /></div><Bookmark size={24} className="hover:text-gray-500 cursor-pointer text-black" /></div>
              <div className="text-sm flex items-center gap-2 text-black"><span className="font-semibold text-black">Archived Post</span><span className="text-gray-400 font-normal text-xs text-black">{post.id}</span></div>
            </div>
          </div>
        </motion.div>
      </div>
    </motion.div>
  );
};
