import React, { useCallback, useEffect, useRef, useState, useMemo } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useTranslation } from "react-i18next";
import { Room, RoomEvent } from "livekit-client";
import maplibregl from "maplibre-gl";
import { useAuth } from "../../auth/AuthContext";
import {
  recordPostView,
  togglePostLike,
  recordPostShare,
  fetchPostComments,
  createPostComment,
  fetchPostLikeState,
  fetchPostTruth,
  votePostTruth,
  editPost,
  deletePost,
  updatePostVisibility,
  fetchProfile,
} from "../../api/client";

// ============================================================================
// CONSTANTS
// ============================================================================
const LIVEKIT_URL = "wss://stream.sociowire.com";
const LIVEKIT_API = "https://stream.sociowire.com";
const MAPTILER_KEY = "DvwhzlPmC55ZK28nLtXL";
const MEDIA_CDN = ""; // Use relative paths - served from same origin

// ============================================================================
// UTILITIES
// ============================================================================
function normalizeMediaUrl(url) {
  if (!url) return "";
  if (url.startsWith("http://") || url.startsWith("https://")) return url;
  if (url.startsWith("/")) return `${MEDIA_CDN}${url}`;
  return `${MEDIA_CDN}/${url}`;
}

function formatCount(n) {
  if (n == null) return "0";
  const num = Number(n) || 0;
  if (num >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M";
  if (num >= 1_000) return (num / 1_000).toFixed(1).replace(/\.0$/, "") + "K";
  return num.toString();
}

function categoryIconClass(post) {
  const c = (post?.category || "NEWS").toString().toUpperCase();
  switch (c) {
    case "EVENT":
    case "EVENTS":
      return "fa-regular fa-calendar";
    case "FRIENDS":
      return "fa-solid fa-user-group";
    case "MARKET":
      return "fa-solid fa-store";
    case "CAMERA":
      return "fa-solid fa-video";
    case "LIVE":
      return "fa-solid fa-tower-broadcast";
    default:
      return "fa-regular fa-newspaper";
  }
}

function relativeTime(dateStr, t) {
  if (!dateStr) return "";
  const d = new Date(dateStr);
  const now = new Date();
  const diff = Math.floor((now - d) / 1000);
  if (diff < 60) return t("time.now");
  if (diff < 3600) return t("time.minutes", { count: Math.floor(diff / 60) });
  if (diff < 86400) return t("time.hours", { count: Math.floor(diff / 3600) });
  if (diff < 604800) return t("time.days", { count: Math.floor(diff / 86400) });
  return d.toLocaleDateString();
}

function getPostType(post) {
  if (!post) return "link";
  const embedUrl = (post.embed_url || "").toString().toLowerCase();
  const videoUrl = (post.video_url || "").toString().toLowerCase();
  const category = (post.category || "").toString().toLowerCase();
  const contentType = (post.content_type || "").toString().toLowerCase();
  const url = (post.url || "").toString();
  const snippet = (post.snippet || post.summary || "").toString();

  if (category === "camera" || contentType === "camera" || post.template === "camera" ||
      embedUrl.includes("quebec511") || embedUrl.includes("511")) return "camera";
  if (embedUrl.startsWith("livekit://") || videoUrl.startsWith("livekit://") ||
      category === "live" || contentType === "live") return "live";
  if (post.video_url) return "video";
  if (["photo", "picture", "image", "gallery"].includes(contentType) ||
      (hasImages(post) && snippet.length < 100 && !url)) return "picture";
  if (["text", "post", "story", "status"].includes(contentType) ||
      (snippet.length > 100 && !url && !hasImages(post))) return "story";
  return "link";
}

function hasImages(post) {
  return !!(post?.image_url || post?.thumbnail_url ||
    (Array.isArray(post?.media_urls) && post.media_urls.length > 0) ||
    (Array.isArray(post?.image_urls) && post.image_urls.length > 0) ||
    (Array.isArray(post?.media) && post.media.length > 0));
}

function getLiveKitRoomName(post) {
  const raw = (post?.embed_url || post?.video_url || "").toString().trim();
  return raw.startsWith("livekit://") ? raw.slice("livekit://".length) : raw;
}

function getHeroImage(post) {
  if (post?.image_url) return normalizeMediaUrl(post.image_url);
  if (post?.thumbnail_url) return normalizeMediaUrl(post.thumbnail_url);
  const media = post?.media;
  if (Array.isArray(media) && media.length > 0) {
    return normalizeMediaUrl(media[0]?.url || media[0]?.thumbnail_url || "");
  }
  return "";
}

function getSourceDomain(url) {
  if (!url) return null;
  try { return new URL(url).hostname.replace(/^www\./, ""); } catch { return null; }
}

const CATEGORY_CONFIG = {
  news: { icon: "fa-newspaper", gradient: "from-blue-500 to-cyan-500", color: "#60a5fa" },
  politics: { icon: "fa-landmark", gradient: "from-purple-500 to-indigo-500", color: "#a78bfa" },
  technology: { icon: "fa-microchip", gradient: "from-emerald-500 to-teal-500", color: "#34d399" },
  science: { icon: "fa-flask", gradient: "from-violet-500 to-purple-500", color: "#8b5cf6" },
  health: { icon: "fa-heart-pulse", gradient: "from-rose-500 to-pink-500", color: "#fb7185" },
  sports: { icon: "fa-futbol", gradient: "from-orange-500 to-amber-500", color: "#fb923c" },
  entertainment: { icon: "fa-film", gradient: "from-pink-500 to-rose-500", color: "#f472b6" },
  business: { icon: "fa-briefcase", gradient: "from-slate-500 to-zinc-500", color: "#94a3b8" },
  environment: { icon: "fa-leaf", gradient: "from-green-500 to-emerald-500", color: "#22c55e" },
  weather: { icon: "fa-cloud-sun", gradient: "from-sky-500 to-blue-500", color: "#38bdf8" },
  traffic: { icon: "fa-car", gradient: "from-yellow-500 to-amber-500", color: "#fbbf24" },
  live: { icon: "fa-broadcast-tower", gradient: "from-red-500 to-rose-500", color: "#ef4444" },
  camera: { icon: "fa-video", gradient: "from-red-500 to-rose-500", color: "#ef4444" },
  events: { icon: "fa-calendar", gradient: "from-yellow-500 to-orange-500", color: "#eab308" },
  event: { icon: "fa-calendar", gradient: "from-yellow-500 to-orange-500", color: "#eab308" },
  friends: { icon: "fa-user-group", gradient: "from-green-500 to-emerald-500", color: "#22c55e" },
  market: { icon: "fa-store", gradient: "from-amber-500 to-orange-500", color: "#f59e0b" },
  default: { icon: "fa-newspaper", gradient: "from-blue-500 to-cyan-500", color: "#60a5fa" },
};

function getCategoryConfig(category) {
  return CATEGORY_CONFIG[(category || "").toLowerCase()] || CATEGORY_CONFIG.default;
}

// ============================================================================
// HERO COMPONENTS
// ============================================================================

function HeroLive({ post, authToken, username }) {
  const roomName = getLiveKitRoomName(post);
  const userID = username || `viewer_${Date.now()}`;
  const [isConnecting, setIsConnecting] = useState(true);
  const [error, setError] = useState(null);
  const [viewerCount, setViewerCount] = useState(0);
  const [videoTrack, setVideoTrack] = useState(null);
  const roomRef = useRef(null);
  const videoRef = useRef(null);

  const getToken = useCallback(async () => {
    const res = await fetch(`${LIVEKIT_API}/api/livekit/token`, {
      method: "POST",
      headers: { "Content-Type": "application/json", ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}) },
      body: JSON.stringify({ room: roomName, identity: userID, name: username || userID, canPublish: false, canSubscribe: true, canPublishData: true }),
    });
    if (!res.ok) throw new Error("Failed to get LiveKit token");
    return (await res.json()).token;
  }, [authToken, roomName, userID, username]);

  useEffect(() => {
    if (!roomName) { setError("Missing room"); setIsConnecting(false); return; }
    let mounted = true;
    const connect = async () => {
      setIsConnecting(true);
      try {
        const token = await getToken();
        if (!mounted) return;
        const room = new Room({ adaptiveStream: true, dynacast: true });
        roomRef.current = room;
        room.on(RoomEvent.TrackSubscribed, (track) => { if (track.kind === "video") setVideoTrack(track); });
        room.on(RoomEvent.ParticipantConnected, () => setViewerCount(p => p + 1));
        room.on(RoomEvent.ParticipantDisconnected, () => setViewerCount(p => Math.max(0, p - 1)));
        room.on(RoomEvent.Disconnected, () => setViewerCount(0));
        await room.connect(LIVEKIT_URL, token);
        setViewerCount(room.participants?.size || 0);
      } catch (err) { if (mounted) setError(err.message); }
      finally { if (mounted) setIsConnecting(false); }
    };
    connect();
    return () => { mounted = false; roomRef.current?.disconnect(); roomRef.current = null; };
  }, [roomName, getToken]);

  useEffect(() => {
    if (!videoRef.current || !videoTrack) return;
    videoTrack.attach(videoRef.current);
    return () => { try { videoTrack.detach(videoRef.current); } catch {} };
  }, [videoTrack]);

  return (
    <div className="absolute inset-0 bg-black">
      <div className="absolute top-4 left-4 z-20 flex items-center gap-2">
        <div className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-red-600 text-white text-xs font-bold shadow-lg shadow-red-600/50">
          <span className="w-2 h-2 rounded-full bg-white animate-pulse" />
          LIVE
        </div>
        <div className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-black/60 backdrop-blur-sm text-white text-xs">
          <i className="fa-solid fa-eye" />
          <span>{viewerCount}</span>
        </div>
      </div>
      {isConnecting ? (
        <div className="absolute inset-0 flex flex-col items-center justify-center">
          <motion.div className="w-20 h-20 rounded-full bg-red-500/20 flex items-center justify-center"
            animate={{ scale: [1, 1.1, 1] }} transition={{ duration: 1.5, repeat: Infinity }}>
            <i className="fa-solid fa-spinner fa-spin text-3xl text-red-400" />
          </motion.div>
        </div>
      ) : error ? (
        <div className="absolute inset-0 flex flex-col items-center justify-center text-red-400">
          <i className="fa-solid fa-exclamation-triangle text-4xl mb-4" />
          <p className="text-sm">{error}</p>
        </div>
      ) : (
        <video ref={videoRef} autoPlay playsInline controls className="w-full h-full object-contain" />
      )}
    </div>
  );
}

// Extract camera ID from Quebec 511 URL like https://www.quebec511.info/Carte/Fenetres/FenetreVideo.html?id=3978
function extractCameraId(url) {
  if (!url) return null;
  const match = url.match(/[?&]id=(\d+)/);
  return match ? match[1] : null;
}

// Build stream proxy URL for Quebec511 cameras
function getCameraStreamUrl(embedUrl, videoUrl) {
  const url = embedUrl || videoUrl || '';
  const cameraId = extractCameraId(url);
  if (cameraId) {
    return `/live/api/stream/${cameraId}`;
  }
  return url;
}

function HeroCamera({ post }) {
  const embedUrl = (post?.embed_url || "").toString().trim();
  const videoUrl = (post?.video_url || "").toString().trim();
  const mapRef = useRef(null);
  const mapContainerRef = useRef(null);
  const lat = Number(post?.lat || post?.latitude);
  const lng = Number(post?.lng || post?.longitude || post?.lon);
  const hasLocation = Number.isFinite(lat) && Number.isFinite(lng);

  // Check if this is a Quebec511 camera
  const isQuebec511 = embedUrl.includes('quebec511') || embedUrl.includes('511');
  const streamUrl = isQuebec511 ? getCameraStreamUrl(embedUrl, videoUrl) : null;

  useEffect(() => {
    if (!mapContainerRef.current || !hasLocation || mapRef.current) return;
    const map = new maplibregl.Map({
      container: mapContainerRef.current,
      style: `https://api.maptiler.com/maps/streets-v2-dark/style.json?key=${MAPTILER_KEY}`,
      center: [lng, lat], zoom: 13, attributionControl: false, interactive: false,
    });
    const el = document.createElement("div");
    el.className = "w-6 h-6 rounded-full bg-red-500 border-2 border-white flex items-center justify-center shadow-lg";
    el.innerHTML = `<i class="fa-solid fa-video text-xs text-white"></i>`;
    new maplibregl.Marker({ element: el }).setLngLat([lng, lat]).addTo(map);
    mapRef.current = map;
    return () => { map.remove(); mapRef.current = null; };
  }, [hasLocation, lat, lng]);

  return (
    <div className="absolute inset-0 bg-black">
      <div className="absolute top-4 left-4 z-20 flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-red-600 text-white text-xs font-bold shadow-lg shadow-red-600/50">
        <span className="w-2 h-2 rounded-full bg-white animate-pulse" />
        LIVE
      </div>
      {isQuebec511 && streamUrl ? (
        // Quebec511 cameras use proxy video stream
        <video src={streamUrl} autoPlay muted playsInline controls loop className="absolute inset-0 w-full h-full object-contain" />
      ) : embedUrl ? (
        // Other cameras use iframe
        <iframe src={embedUrl} title={post?.title || "Camera"} allow="autoplay; encrypted-media" allowFullScreen className="absolute inset-0 w-full h-full border-0" />
      ) : videoUrl ? (
        <video src={videoUrl} autoPlay muted playsInline controls className="absolute inset-0 w-full h-full object-contain" />
      ) : (
        <div className="absolute inset-0 flex flex-col items-center justify-center text-surface-500">
          <i className="fa-solid fa-video-slash text-5xl mb-4 opacity-50" />
          <span>Stream unavailable</span>
          {(embedUrl || videoUrl) && (
            <a href={embedUrl || videoUrl} target="_blank" rel="noopener noreferrer"
               className="mt-4 px-4 py-2 rounded-lg bg-accent text-white text-sm">
              Open external link
            </a>
          )}
        </div>
      )}
      {hasLocation && (
        <div ref={mapContainerRef} className="absolute bottom-4 right-4 w-36 h-28 rounded-xl overflow-hidden border-2 border-white/20 shadow-2xl z-10" />
      )}
    </div>
  );
}

function HeroVideo({ post }) {
  return (
    <div className="absolute inset-0 bg-black flex items-center justify-center">
      <video controls playsInline className="max-w-full max-h-full object-contain"
        src={normalizeMediaUrl(post?.video_url)} poster={getHeroImage(post)} />
    </div>
  );
}

function HeroPicture({ gallery, imageIndex, setImageIndex, post, onFullscreen }) {
  const currentImage = gallery[imageIndex] || getHeroImage(post);
  if (!currentImage) return (
    <div className="absolute inset-0 flex items-center justify-center bg-surface-900 text-surface-500">
      <i className="fa-solid fa-image text-6xl opacity-30" />
    </div>
  );
  return (
    <div className="absolute inset-0 bg-black">
      <img src={currentImage} alt="" className="w-full h-full object-contain cursor-zoom-in" onClick={onFullscreen} />
      {gallery.length > 1 && (
        <>
          <button className="absolute left-3 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/60 backdrop-blur-sm text-white flex items-center justify-center hover:bg-black/80 transition-colors"
            onClick={() => setImageIndex((i) => (i - 1 + gallery.length) % gallery.length)}>
            <i className="fa-solid fa-chevron-left text-lg" />
          </button>
          <button className="absolute right-3 top-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-black/60 backdrop-blur-sm text-white flex items-center justify-center hover:bg-black/80 transition-colors"
            onClick={() => setImageIndex((i) => (i + 1) % gallery.length)}>
            <i className="fa-solid fa-chevron-right text-lg" />
          </button>
          <div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
            {gallery.map((_, i) => (
              <button key={i} onClick={() => setImageIndex(i)}
                className={`w-2.5 h-2.5 rounded-full transition-all ${i === imageIndex ? "bg-white w-6" : "bg-white/40 hover:bg-white/60"}`} />
            ))}
          </div>
        </>
      )}
      <button className="absolute top-4 right-4 w-10 h-10 rounded-full bg-black/60 backdrop-blur-sm text-white flex items-center justify-center hover:bg-black/80"
        onClick={onFullscreen}>
        <i className="fa-solid fa-expand" />
      </button>
    </div>
  );
}

function HeroStory({ post, gallery, imageIndex, setImageIndex }) {
  const heroImage = gallery[imageIndex] || getHeroImage(post);
  const author = post?.author || post?.username || "Anonymous";
  const config = getCategoryConfig(post?.category);

  // If has image, show it like HeroLink
  if (heroImage) {
    return (
      <div className="absolute inset-0">
        <img src={heroImage} alt="" className="w-full h-full object-cover" />
        <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-black/30" />
        {gallery.length > 1 && (
          <>
            <button className="absolute left-3 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/60 backdrop-blur-sm text-white flex items-center justify-center hover:bg-black/80"
              onClick={() => setImageIndex((i) => (i - 1 + gallery.length) % gallery.length)}>
              <i className="fa-solid fa-chevron-left" />
            </button>
            <button className="absolute right-3 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-black/60 backdrop-blur-sm text-white flex items-center justify-center hover:bg-black/80"
              onClick={() => setImageIndex((i) => (i + 1) % gallery.length)}>
              <i className="fa-solid fa-chevron-right" />
            </button>
            <div className="absolute bottom-4 right-4 px-3 py-1.5 rounded-full bg-black/60 backdrop-blur-sm text-white text-xs">
              {imageIndex + 1} / {gallery.length}
            </div>
          </>
        )}
      </div>
    );
  }

  // No image - show gradient with category icon
  return (
    <div className={`absolute inset-0 bg-gradient-to-br ${config.gradient}`}>
      <div className="absolute inset-0 flex flex-col items-center justify-center gap-3">
        <div className="w-20 h-20 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center text-white shadow-lg">
          <i className={`${categoryIconClass(post)} text-4xl`} />
        </div>
        <span className="text-white/80 text-sm font-medium uppercase tracking-wider">{post?.category || "News"}</span>
      </div>
    </div>
  );
}

function HeroLink({ post, gallery, imageIndex, setImageIndex }) {
  const heroImage = getHeroImage(post);
  const sourceDomain = getSourceDomain(post?.url);
  const config = getCategoryConfig(post?.category);

  if (!heroImage) {
    return (
      <div className={`absolute inset-0 flex flex-col items-center justify-center bg-gradient-to-br ${config.gradient}`}>
        <i className={`fa-solid ${config.icon} text-7xl text-white/80 mb-4`} />
        <span className="text-white/60 text-lg font-medium">{post?.category || "Article"}</span>
      </div>
    );
  }
  return (
    <div className="absolute inset-0">
      <img src={gallery[imageIndex] || heroImage} alt="" className="w-full h-full object-cover" />
      <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-black/30" />
      {sourceDomain && (
        <div className="absolute bottom-4 left-4 flex items-center gap-2 px-4 py-2 rounded-full bg-black/60 backdrop-blur-md text-white text-sm font-medium">
          <i className="fa-solid fa-link text-accent" />
          <span>{sourceDomain}</span>
        </div>
      )}
      {gallery.length > 1 && (
        <div className="absolute bottom-4 right-4 px-3 py-1.5 rounded-full bg-black/60 backdrop-blur-sm text-white text-xs">
          {imageIndex + 1} / {gallery.length}
        </div>
      )}
    </div>
  );
}

// ============================================================================
// FULLSCREEN GALLERY
// ============================================================================
function FullscreenGallery({ gallery, imageIndex, setImageIndex, onClose }) {
  useEffect(() => {
    const handleKey = (e) => {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowLeft") setImageIndex((i) => (i - 1 + gallery.length) % gallery.length);
      if (e.key === "ArrowRight") setImageIndex((i) => (i + 1) % gallery.length);
    };
    window.addEventListener("keydown", handleKey);
    return () => window.removeEventListener("keydown", handleKey);
  }, [gallery.length, onClose, setImageIndex]);

  return (
    <motion.div className="fixed inset-0 z-[2000] bg-black flex items-center justify-center"
      initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} onClick={onClose}>
      <img src={gallery[imageIndex]} alt="" className="max-w-full max-h-full object-contain" onClick={(e) => e.stopPropagation()} />
      {gallery.length > 1 && (
        <>
          <button className="absolute left-4 top-1/2 -translate-y-1/2 w-14 h-14 rounded-full bg-white/10 backdrop-blur-sm text-white flex items-center justify-center hover:bg-white/20"
            onClick={(e) => { e.stopPropagation(); setImageIndex((i) => (i - 1 + gallery.length) % gallery.length); }}>
            <i className="fa-solid fa-chevron-left text-2xl" />
          </button>
          <button className="absolute right-4 top-1/2 -translate-y-1/2 w-14 h-14 rounded-full bg-white/10 backdrop-blur-sm text-white flex items-center justify-center hover:bg-white/20"
            onClick={(e) => { e.stopPropagation(); setImageIndex((i) => (i + 1) % gallery.length); }}>
            <i className="fa-solid fa-chevron-right text-2xl" />
          </button>
        </>
      )}
      <button className="absolute top-4 right-4 w-12 h-12 rounded-full bg-white/10 backdrop-blur-sm text-white flex items-center justify-center hover:bg-white/20"
        onClick={onClose}>
        <i className="fa-solid fa-times text-xl" />
      </button>
      {gallery.length > 1 && (
        <div className="absolute bottom-6 left-1/2 -translate-x-1/2 px-4 py-2 rounded-full bg-white/10 backdrop-blur-sm text-white">
          {imageIndex + 1} / {gallery.length}
        </div>
      )}
    </motion.div>
  );
}

// ============================================================================
// MAIN COMPONENT
// ============================================================================
export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDeleted }) {
  const { t } = useTranslation();
  const { username, token } = useAuth();
  const modalRef = useRef(null);

  // State
  const [counts, setCounts] = useState({
    views: post?.view_count || 0, likes: post?.like_count || 0,
    shares: post?.share_count || 0, comments: post?.comment_count || 0,
  });
  const [liked, setLiked] = useState(false);
  const [truth, setTruth] = useState({ score: 50, count: 0 });
  const [authorAvatar, setAuthorAvatar] = useState("");
  const [commenterAvatars, setCommenterAvatars] = useState({});
  const [comments, setComments] = useState([]);
  const [commentInput, setCommentInput] = useState("");
  const [commentSending, setCommentSending] = useState(false);
  const [showComments, setShowComments] = useState(false);
  const [showEdit, setShowEdit] = useState(false);
  const [showDelete, setShowDelete] = useState(false);
  const [editTitle, setEditTitle] = useState(post?.title || "");
  const [editSnippet, setEditSnippet] = useState(post?.snippet || "");
  const [saving, setSaving] = useState(false);
  const [imageIndex, setImageIndex] = useState(0);
  const [fullscreen, setFullscreen] = useState(false);

  const commentsEndRef = useRef(null);
  const justCommentedRef = useRef(false);
  const postId = post?.id || post?._id;
  const isAuthor = username && (post?.author === username || post?.username === username);
  const postType = useMemo(() => getPostType(post), [post]);
  const config = getCategoryConfig(post?.category);
  const author = post?.author || post?.username || post?.source_name || t("common.anon");

  // Media gallery
  const gallery = useMemo(() => {
    const seen = new Set();
    const images = [];
    const add = (url) => { const n = normalizeMediaUrl(url); if (n && !seen.has(n)) { seen.add(n); images.push(n); } };
    [post?.media_urls, post?.image_urls].forEach(arr => arr?.forEach(add));
    [post?.image_large, post?.image_medium, post?.image_small, post?.image_url, post?.image].forEach(add);
    post?.media?.forEach(m => add(m?.url || m?.thumbnail_url));
    return images;
  }, [post]);

  // Initial data fetch
  useEffect(() => {
    if (!postId) return;
    recordPostView(postId).then(res => {
      if (res?.counts) setCounts(c => ({ ...c, views: res.counts.view_count || c.views, likes: res.counts.like_count || c.likes }));
    });
    fetchPostLikeState(postId).then(res => { if (res?.liked !== undefined) setLiked(res.liked); });
    fetchPostTruth(postId).then(res => { if (res) setTruth({ score: res.truth_score ?? res.user_score ?? 50, count: res.vote_count ?? 0 }); });
  }, [postId]);

  // Fetch author avatar
  useEffect(() => {
    const authorName = post?.author || post?.username;
    if (!authorName) return;
    fetchProfile(authorName).then(res => {
      if (res?.avatar_url) setAuthorAvatar(res.avatar_url);
    });
  }, [post?.author, post?.username]);

  // Fetch commenter avatars
  useEffect(() => {
    if (!comments.length) return;
    const usernames = [...new Set(comments.map(c => c.username).filter(Boolean))];
    // Only fetch for usernames we don't already have
    const toFetch = usernames.filter(u => !commenterAvatars[u]);
    if (!toFetch.length) return;
    toFetch.forEach(username => {
      fetchProfile(username).then(res => {
        if (res?.avatar_url) {
          setCommenterAvatars(prev => ({ ...prev, [username]: res.avatar_url }));
        }
      });
    });
  }, [comments]);

  // Fetch comments
  const refreshComments = useCallback(async (autoOpen = false) => {
    if (!postId) return;
    const items = await fetchPostComments(postId, 50);
    if (Array.isArray(items)) {
      setComments(items);
      setCounts(c => ({ ...c, comments: items.length }));
      if (autoOpen && items.length > 0) setShowComments(true);
    }
  }, [postId]);

  useEffect(() => { refreshComments(true); }, [refreshComments]);
  useEffect(() => {
    // Only scroll to bottom when user just added a comment, not on initial load
    if (showComments && justCommentedRef.current) {
      commentsEndRef.current?.scrollIntoView({ behavior: "smooth" });
      justCommentedRef.current = false;
    }
  }, [comments, showComments]);

  // Handlers
  const handleLike = useCallback(async () => {
    if (!postId) return;
    const newLiked = !liked;
    setLiked(newLiked);
    setCounts(c => ({ ...c, likes: c.likes + (newLiked ? 1 : -1) }));
    const res = await togglePostLike(postId, newLiked);
    if (res?.counts) setCounts(c => ({ ...c, likes: res.counts.like_count ?? c.likes }));
  }, [postId, liked]);

  const handleShare = useCallback(async () => {
    if (!postId) return;
    const shareUrl = `${window.location.origin}/post/${postId}`;
    if (navigator.share) { try { await navigator.share({ title: post?.title, url: shareUrl }); } catch {} }
    else { navigator.clipboard?.writeText(shareUrl); }
    const res = await recordPostShare(postId);
    if (res?.counts) setCounts(c => ({ ...c, shares: res.counts.share_count ?? c.shares }));
  }, [postId, post?.title]);

  const handleTruthVote = useCallback(async (vote) => {
    if (!postId) return;
    const res = await votePostTruth(postId, vote);
    if (res) setTruth({ score: res.truth_score ?? res.user_score ?? truth.score, count: res.vote_count ?? truth.count });
  }, [postId, truth]);

  const handleComment = useCallback(async () => {
    const body = commentInput.trim();
    if (!body || !postId || commentSending) return;
    setCommentInput("");
    setCommentSending(true);
    const tempId = `temp_${Date.now()}`;
    const newComment = { id: tempId, body, username: username || "You", created_at: new Date().toISOString(), _pending: true };
    justCommentedRef.current = true;
    setComments(prev => [...prev, newComment]);
    setCounts(c => ({ ...c, comments: c.comments + 1 }));
    const res = await createPostComment(postId, body);
    setCommentSending(false);
    if (res?.ok) {
      // Success - update with server response or just mark as complete
      if (res?.comment) {
        setComments(prev => prev.map(c => c.id === tempId ? { ...res.comment, _pending: false } : c));
      } else {
        setComments(prev => prev.map(c => c.id === tempId ? { ...c, _pending: false } : c));
      }
      // Delay refresh to let backend commit
      setTimeout(() => refreshComments(), 500);
    } else {
      setComments(prev => prev.map(c => c.id === tempId ? { ...c, _failed: true, _pending: false } : c));
    }
  }, [commentInput, postId, commentSending, username]);

  const handleSaveEdit = useCallback(async () => {
    if (!postId || saving) return;
    setSaving(true);
    const res = await editPost(postId, { title: editTitle, snippet: editSnippet }, token);
    setSaving(false);
    if (res?.ok) { setShowEdit(false); onPostUpdated?.({ ...post, title: editTitle, snippet: editSnippet }); }
  }, [postId, editTitle, editSnippet, token, saving, post, onPostUpdated]);

  const handleDelete = useCallback(async () => {
    if (!postId || saving) return;
    setSaving(true);
    const res = await deletePost(postId, token);
    setSaving(false);
    if (res?.ok) { onPostDeleted?.(postId); onClose?.(); }
  }, [postId, token, saving, onPostDeleted, onClose]);

  // Close on escape + prevent body scroll
  useEffect(() => {
    const handleKey = (e) => { if (e.key === "Escape" && !fullscreen) onClose?.(); };
    window.addEventListener("keydown", handleKey);

    // Prevent body scroll when modal is open
    const originalOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';

    return () => {
      window.removeEventListener("keydown", handleKey);
      document.body.style.overflow = originalOverflow;
    };
  }, [onClose, fullscreen]);

  if (!post) return null;

  return (
    <>
      <motion.div
        className="fixed inset-0 z-[1100] flex items-center justify-center p-2 sm:p-4 bg-black/90 backdrop-blur-md"
        initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
        onClick={(e) => { if (e.target === e.currentTarget) onClose?.(); }}
      >
        <motion.div
          ref={modalRef}
          className="relative w-full max-w-5xl max-h-[95vh] overflow-hidden rounded-2xl sm:rounded-3xl
                     bg-themed-secondary border border-themed shadow-2xl"
          initial={{ scale: 0.9, y: 50, opacity: 0 }}
          animate={{ scale: 1, y: 0, opacity: 1 }}
          exit={{ scale: 0.9, y: 50, opacity: 0 }}
          transition={{ type: "spring", damping: 30, stiffness: 400 }}
          onClick={(e) => e.stopPropagation()}
        >
          {/* Hero Section */}
          <div className="relative aspect-[16/9] sm:aspect-video bg-surface-950 overflow-hidden">
            {postType === "live" ? <HeroLive post={post} authToken={token} username={username} />
             : postType === "camera" ? <HeroCamera post={post} />
             : postType === "video" ? <HeroVideo post={post} />
             : postType === "picture" ? <HeroPicture gallery={gallery} imageIndex={imageIndex} setImageIndex={setImageIndex} post={post} onFullscreen={() => setFullscreen(true)} />
             : postType === "story" ? <HeroStory post={post} gallery={gallery} imageIndex={imageIndex} setImageIndex={setImageIndex} />
             : <HeroLink post={post} gallery={gallery} imageIndex={imageIndex} setImageIndex={setImageIndex} />}

            {/* Close Button */}
            <motion.button
              className="absolute top-3 right-3 sm:top-4 sm:right-4 w-10 h-10 sm:w-11 sm:h-11 rounded-full bg-black/60 backdrop-blur-md
                         flex items-center justify-center text-white hover:bg-black/80 transition-colors z-30"
              whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} onClick={onClose}>
              <i className="fa-solid fa-times text-lg" />
            </motion.button>

            {/* Category Badge */}
            <div className="absolute top-3 left-3 sm:top-4 sm:left-4 z-20">
              <div className={`flex items-center gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-gradient-to-r ${config.gradient}
                              text-white text-xs sm:text-sm font-bold uppercase tracking-wide shadow-lg`}>
                <i className={`fa-solid ${config.icon}`} />
                <span>{post?.category || "News"}</span>
                {(postType === "live" || postType === "camera") && <span className="w-2 h-2 rounded-full bg-white animate-pulse" />}
              </div>
            </div>
          </div>

          {/* Content Section */}
          <div className="max-h-[50vh] overflow-y-auto">
            <div className="p-4 sm:p-6">
              {/* Title */}
              {post?.title && (
                <h1 className="text-xl sm:text-2xl font-bold text-themed-primary leading-tight mb-4">
                  {post.title}
                </h1>
              )}

              {/* Author Row */}
              <div className="flex items-center gap-3 mb-4">
                <div className={`w-11 h-11 sm:w-12 sm:h-12 rounded-full bg-gradient-to-br ${config.gradient} flex items-center justify-center
                                text-white font-bold text-base sm:text-lg shadow-lg overflow-hidden`}>
                  {authorAvatar ? (
                    <img src={authorAvatar} alt={author} className="w-full h-full object-cover" />
                  ) : (
                    author.charAt(0).toUpperCase()
                  )}
                </div>
                <div className="flex-1 min-w-0">
                  <p className="font-semibold text-themed-primary truncate">@{author}</p>
                  <p className="text-sm text-themed-muted">{relativeTime(post?.published_at || post?.created_at, t)}</p>
                </div>
                {isAuthor && (
                  <div className="flex gap-2">
                    <motion.button whileTap={{ scale: 0.9 }} onClick={() => setShowEdit(!showEdit)}
                      className="w-9 h-9 rounded-full bg-themed-accent flex items-center justify-center text-accent">
                      <i className="fa-solid fa-pen text-sm" />
                    </motion.button>
                    <motion.button whileTap={{ scale: 0.9 }} onClick={() => setShowDelete(!showDelete)}
                      className="w-9 h-9 rounded-full bg-red-500/20 flex items-center justify-center text-red-400">
                      <i className="fa-solid fa-trash text-sm" />
                    </motion.button>
                  </div>
                )}
              </div>

              {/* Edit Panel */}
              <AnimatePresence>
                {showEdit && (
                  <motion.div className="mb-4 p-4 rounded-2xl bg-themed-elevated border border-themed"
                    initial={{ height: 0, opacity: 0 }} animate={{ height: "auto", opacity: 1 }} exit={{ height: 0, opacity: 0 }}>
                    <input type="text" value={editTitle} onChange={(e) => setEditTitle(e.target.value)} placeholder={t("post.title")}
                      className="w-full px-4 py-3 mb-3 rounded-xl bg-themed-primary border border-themed text-themed-primary placeholder:text-themed-muted focus:outline-none focus:border-accent" />
                    <textarea value={editSnippet} onChange={(e) => setEditSnippet(e.target.value)} placeholder={t("post.description")} rows={3}
                      className="w-full px-4 py-3 mb-3 rounded-xl bg-themed-primary border border-themed text-themed-primary placeholder:text-themed-muted focus:outline-none focus:border-accent resize-none" />
                    <div className="flex gap-2">
                      <button onClick={handleSaveEdit} disabled={saving}
                        className="flex-1 py-3 rounded-xl bg-accent text-white font-semibold hover:opacity-90 disabled:opacity-50">
                        {saving ? t("post.saving") : t("common.save")}
                      </button>
                      <button onClick={() => setShowEdit(false)} className="flex-1 py-3 rounded-xl bg-themed-elevated border border-themed text-themed-secondary">
                        {t("common.cancel")}
                      </button>
                    </div>
                  </motion.div>
                )}
              </AnimatePresence>

              {/* Delete Confirm */}
              <AnimatePresence>
                {showDelete && (
                  <motion.div className="mb-4 p-4 rounded-2xl bg-red-500/10 border border-red-500/30"
                    initial={{ height: 0, opacity: 0 }} animate={{ height: "auto", opacity: 1 }} exit={{ height: 0, opacity: 0 }}>
                    <p className="text-red-400 text-center mb-4">{t("post.deletePost")}</p>
                    <div className="flex gap-2">
                      <button onClick={handleDelete} disabled={saving}
                        className="flex-1 py-3 rounded-xl bg-red-500 text-white font-semibold hover:bg-red-600 disabled:opacity-50">
                        {saving ? t("post.deleting") : t("common.delete")}
                      </button>
                      <button onClick={() => setShowDelete(false)} className="flex-1 py-3 rounded-xl bg-themed-elevated border border-themed text-themed-secondary">
                        {t("common.cancel")}
                      </button>
                    </div>
                  </motion.div>
                )}
              </AnimatePresence>

              {/* Description / Story Text */}
              {(post?.snippet || post?.summary) && (
                <div className={`text-themed-secondary text-base leading-relaxed mb-4 ${postType === "story" ? "whitespace-pre-wrap" : ""}`}>
                  {post?.snippet || post?.summary}
                </div>
              )}

              {/* Tags */}
              {post?.tags?.length > 0 && (
                <div className="flex flex-wrap gap-2 mb-4">
                  {post.tags.slice(0, 6).map((tag, i) => (
                    <span key={i} className="px-3 py-1.5 rounded-full bg-themed-accent text-accent text-xs font-medium">
                      #{tag}
                    </span>
                  ))}
                </div>
              )}

              {/* Source Link */}
              {post?.url && (
                <a href={post.url} target="_blank" rel="noopener noreferrer"
                  className="inline-flex items-center gap-3 px-5 py-3 rounded-xl bg-themed-elevated border border-themed
                             text-themed-primary hover:border-accent hover:text-accent transition-all group">
                  <i className="fa-solid fa-external-link-alt text-accent" />
                  <span className="truncate max-w-xs">{getSourceDomain(post.url) || post.url}</span>
                  <i className="fa-solid fa-arrow-right text-themed-muted group-hover:text-accent group-hover:translate-x-1 transition-all" />
                </a>
              )}

              {/* Stats & Actions */}
              <div className="mt-6 pt-4 border-t border-themed">
                {/* Stats Row */}
                <div className="flex items-center justify-around mb-4">
                  {[
                    { icon: "fa-eye", value: counts.views, label: "views" },
                    { icon: "fa-heart", value: counts.likes, label: "likes" },
                    { icon: "fa-share", value: counts.shares, label: "shares" },
                    { icon: "fa-comment", value: counts.comments, label: "comments" },
                  ].map(({ icon, value, label }) => (
                    <div key={label} className="flex flex-col items-center">
                      <i className={`fa-solid ${icon} text-themed-muted mb-1`} />
                      <span className="text-themed-primary font-bold">{formatCount(value)}</span>
                    </div>
                  ))}
                </div>

                {/* Truth Score */}
                <div className="mb-3 p-2.5 rounded-xl bg-themed-elevated">
                  <div className="flex items-center gap-3">
                    <motion.button whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} onClick={() => handleTruthVote("false")}
                      className="w-9 h-9 rounded-full bg-red-500/20 border border-red-500/30 text-red-400 flex items-center justify-center hover:bg-red-500/30">
                      <i className="fa-solid fa-thumbs-down text-sm" />
                    </motion.button>
                    <div className="flex-1">
                      <div className="flex items-center justify-center gap-1.5 mb-1">
                        <span className={`text-xl font-black ${truth.score >= 70 ? 'text-emerald-400' : truth.score >= 50 ? 'text-amber-400' : 'text-red-400'}`}>
                          {Math.round(truth.score)}
                        </span>
                        <span className="text-themed-muted text-xs">/ 100</span>
                      </div>
                      <div className="h-1.5 rounded-full bg-surface-800 overflow-hidden">
                        <motion.div className={`h-full rounded-full ${truth.score >= 70 ? 'bg-gradient-to-r from-emerald-500 to-teal-400' : truth.score >= 50 ? 'bg-gradient-to-r from-amber-500 to-orange-400' : 'bg-gradient-to-r from-red-500 to-pink-400'}`}
                          initial={{ width: 0 }} animate={{ width: `${truth.score}%` }} transition={{ duration: 0.6 }} />
                      </div>
                      <p className="text-center text-[10px] text-themed-muted mt-0.5">{truth.count} votes</p>
                    </div>
                    <motion.button whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} onClick={() => handleTruthVote("true")}
                      className="w-9 h-9 rounded-full bg-emerald-500/20 border border-emerald-500/30 text-emerald-400 flex items-center justify-center hover:bg-emerald-500/30">
                      <i className="fa-solid fa-thumbs-up text-sm" />
                    </motion.button>
                  </div>
                </div>

                {/* Action Buttons */}
                <div className="grid grid-cols-3 gap-2">
                  <motion.button whileTap={{ scale: 0.95 }} onClick={handleLike}
                    className={`flex items-center justify-center gap-2 py-3 rounded-xl font-semibold transition-all
                               ${liked ? 'bg-pink-500/20 text-pink-400 border border-pink-500/30' : 'bg-themed-elevated text-themed-secondary border border-themed hover:border-pink-500/30 hover:text-pink-400'}`}>
                    <i className={liked ? "fa-solid fa-heart" : "fa-regular fa-heart"} />
                    <span className="hidden sm:inline">{t("post.like")}</span>
                  </motion.button>
                  <motion.button whileTap={{ scale: 0.95 }} onClick={() => setShowComments(!showComments)}
                    className={`flex items-center justify-center gap-2 py-3 rounded-xl font-semibold transition-all
                               ${showComments ? 'bg-accent/20 text-accent border border-accent/30' : 'bg-themed-elevated text-themed-secondary border border-themed hover:border-accent/30 hover:text-accent'}`}>
                    <i className="fa-solid fa-comment" />
                    <span className="hidden sm:inline">{t("post.comment")}</span>
                  </motion.button>
                  <motion.button whileTap={{ scale: 0.95 }} onClick={handleShare}
                    className="flex items-center justify-center gap-2 py-3 rounded-xl bg-themed-elevated text-themed-secondary border border-themed font-semibold hover:border-accent/30 hover:text-accent transition-all">
                    <i className="fa-solid fa-share" />
                    <span className="hidden sm:inline">{t("post.share")}</span>
                  </motion.button>
                </div>
              </div>

              {/* Comments Section */}
              <AnimatePresence>
                {showComments && (
                  <motion.div className="mt-4" initial={{ height: 0, opacity: 0 }} animate={{ height: "auto", opacity: 1 }} exit={{ height: 0, opacity: 0 }}>
                    <div className="p-4 rounded-2xl bg-themed-elevated border border-themed">
                      <div className="flex items-center gap-2 mb-4">
                        <i className="fa-solid fa-comments text-accent" />
                        <span className="font-semibold text-themed-primary">{t("post.comment")}</span>
                        <span className="ml-auto px-2 py-0.5 rounded-full bg-accent/20 text-accent text-xs font-bold">{comments.length}</span>
                      </div>

                      {/* Comments List */}
                      <div className="max-h-64 overflow-y-auto space-y-3 mb-4 scrollbar-thin">
                        {comments.length === 0 ? (
                          <div className="text-center py-8 text-themed-muted">
                            <i className="fa-regular fa-comment-dots text-4xl mb-2 opacity-40" />
                            <p>{t("postModal.noComments")}</p>
                          </div>
                        ) : (
                          comments.map((c) => (
                            <motion.div key={c.id} className={`p-3 rounded-xl bg-themed-primary border border-themed ${c._pending ? "opacity-50" : ""} ${c._failed ? "border-red-500/30" : ""}`}
                              initial={{ opacity: 0, y: 10 }} animate={{ opacity: c._pending ? 0.5 : 1, y: 0 }}>
                              <div className="flex items-start gap-2">
                                <div className={`w-8 h-8 rounded-full bg-gradient-to-br ${config.gradient} flex items-center justify-center text-white text-xs font-bold flex-shrink-0 overflow-hidden`}>
                                  {commenterAvatars[c.username] ? (
                                    <img src={commenterAvatars[c.username]} alt={c.username} className="w-full h-full object-cover" />
                                  ) : (
                                    (c.username || "?")[0]?.toUpperCase()
                                  )}
                                </div>
                                <div className="flex-1 min-w-0">
                                  <div className="flex items-center gap-2 mb-0.5">
                                    <span className="text-xs font-bold text-accent">@{c.username || "user"}</span>
                                    <span className="text-xs text-themed-muted">{relativeTime(c.created_at, t)}</span>
                                    {c._failed && <span className="text-xs text-red-400">Failed</span>}
                                  </div>
                                  <p className="text-sm text-themed-secondary">{c.body}</p>
                                </div>
                              </div>
                            </motion.div>
                          ))
                        )}
                        <div ref={commentsEndRef} />
                      </div>

                      {/* Comment Input */}
                      <div className="flex gap-2">
                        <input type="text" value={commentInput} onChange={(e) => setCommentInput(e.target.value)}
                          onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleComment(); } }}
                          placeholder={token ? t("postModal.writeComment") : t("post.signInToComment")}
                          disabled={!token || commentSending}
                          className="flex-1 px-4 py-3 rounded-xl bg-themed-primary border border-themed text-themed-primary placeholder:text-themed-muted focus:outline-none focus:border-accent disabled:opacity-50" />
                        <motion.button whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}
                          disabled={!token || !commentInput.trim() || commentSending} onClick={handleComment}
                          className="w-12 h-12 rounded-xl bg-accent text-white flex items-center justify-center disabled:opacity-50">
                          {commentSending ? <i className="fa-solid fa-spinner fa-spin" /> : <i className="fa-solid fa-paper-plane" />}
                        </motion.button>
                      </div>
                    </div>
                  </motion.div>
                )}
              </AnimatePresence>
            </div>
          </div>
        </motion.div>
      </motion.div>

      {/* Fullscreen Gallery */}
      <AnimatePresence>
        {fullscreen && gallery.length > 0 && (
          <FullscreenGallery gallery={gallery} imageIndex={imageIndex} setImageIndex={setImageIndex} onClose={() => setFullscreen(false)} />
        )}
      </AnimatePresence>
    </>
  );
}
