import { useCallback, useEffect, useRef, useState } from "react";
import { Room, RoomEvent, DataPacket_Kind } from "livekit-client";
import { useAuth } from "../../auth/AuthContext";
import { fetchPostComments, createPostComment } from "../../api/client";
import "./Live.css";

const LIVEKIT_URL = "wss://stream.sociowire.com";
const LIVEKIT_API = "https://stream.sociowire.com";

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

export default function LiveKitViewerModal({ post, onClose }) {
  const { username, token: authToken } = useAuth();
  const userID = username || `viewer_${Date.now()}`;
  const roomName = roomNameFromPost(post);

  const [isConnecting, setIsConnecting] = useState(false);
  const [error, setError] = useState(null);
  const [viewerCount, setViewerCount] = useState(0);
  const [videoTrack, setVideoTrack] = useState(null);
  const roomRef = useRef(null);
  const videoRef = useRef(null);

  // Comments state
  const [comments, setComments] = useState([]);
  const [commentInput, setCommentInput] = useState("");
  const [commentSending, setCommentSending] = useState(false);
  const commentsEndRef = useRef(null);
  const postId = post?.id || post?._id;

  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, // Allow sending comments via data channel
      }),
    });
    if (!res.ok) {
      throw new Error("Failed to get LiveKit token");
    }
    const data = await res.json();
    return data.token;
  }, [authToken, roomName, userID, username]);

  useEffect(() => {
    if (!roomName) {
      setError("Missing room name");
      return;
    }
    let mounted = true;
    const connect = async () => {
      setIsConnecting(true);
      setError(null);
      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((prev) => prev + 1);
        });
        room.on(RoomEvent.ParticipantDisconnected, () => {
          setViewerCount((prev) => Math.max(0, prev - 1));
        });
        room.on(RoomEvent.Disconnected, () => {
          setViewerCount(0);
        });

        // Handle real-time comments via data channel
        room.on(RoomEvent.DataReceived, (payload, participant) => {
          try {
            const decoder = new TextDecoder();
            const jsonStr = decoder.decode(payload);
            const data = JSON.parse(jsonStr);
            if (data?.type === "comment" && data?.comment) {
              setComments(prev => {
                // Avoid duplicates
                if (prev.some(c => c.id === data.comment.id)) return prev;
                return [...prev, data.comment];
              });
            }
          } catch (err) {
            console.warn("[LiveKit Viewer] Failed to parse data:", err);
          }
        });

        await room.connect(LIVEKIT_URL, token);
        setViewerCount(room.participants?.size || 0);
      } catch (err) {
        if (mounted) {
          setError(err.message || "Failed to connect");
        }
      } finally {
        if (mounted) setIsConnecting(false);
      }
    };
    connect();

    return () => {
      mounted = false;
      if (roomRef.current) {
        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]);

  // Fetch comments (merge with local to preserve optimistic updates)
  const refreshComments = useCallback(async () => {
    if (!postId) return;
    const items = await fetchPostComments(postId, 50);
    if (Array.isArray(items)) {
      setComments(prev => {
        const serverIds = new Set(items.map(c => String(c.id)));
        // Keep local comments (those with underscore in ID that aren't in server response)
        const localOnly = prev.filter(c => {
          const id = String(c.id);
          return id.includes('_') && !serverIds.has(id);
        });
        // Combine: server comments + local-only comments (avoid duplicates by body)
        const serverBodies = new Set(items.map(c => c.body));
        const newLocal = localOnly.filter(c => !serverBodies.has(c.body));
        return [...items, ...newLocal];
      });
    }
  }, [postId]);

  // Initial load + fallback polling (less frequent since we use WebSocket)
  useEffect(() => {
    if (!postId) return;
    let active = true;
    // Initial load
    refreshComments();
    // Fallback poll every 15s in case WebSocket misses something
    const timer = setInterval(() => {
      if (active) refreshComments();
    }, 15000);
    return () => {
      active = false;
      clearInterval(timer);
    };
  }, [postId, refreshComments]);

  // Auto-scroll comments
  useEffect(() => {
    commentsEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [comments]);

  // Send comment via WebSocket + persist to API
  const handleSendComment = useCallback(async () => {
    const body = commentInput.trim();
    if (!body || !postId || commentSending) return;

    setCommentInput("");
    setCommentSending(true);

    const commentId = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const newComment = {
      id: commentId,
      body,
      author: username || "You",
      created_at: new Date().toISOString(),
    };

    // Show locally immediately
    setComments(prev => [...prev, newComment]);

    // Broadcast via WebSocket to all participants (real-time)
    if (roomRef.current?.localParticipant) {
      try {
        const encoder = new TextEncoder();
        const payload = encoder.encode(JSON.stringify({ type: "comment", comment: newComment }));
        await roomRef.current.localParticipant.publishData(payload, DataPacket_Kind.RELIABLE);
      } catch (err) {
        console.warn("[LiveKit Viewer] Failed to broadcast comment:", err);
      }
    }

    // Also persist to API (for replay/history)
    const res = await createPostComment(postId, body);
    setCommentSending(false);

    if (!res?.ok) {
      console.warn("[LiveKit Viewer] Failed to save comment to API:", res);
    }
  }, [commentInput, postId, commentSending, username]);

  const handleClose = useCallback(() => {
    if (roomRef.current) {
      roomRef.current.disconnect();
      roomRef.current = null;
    }
    onClose?.();
  }, [onClose]);

  if (!post) return null;

  return (
    <div className="sw-viewer-modal" onClick={(e) => {
      if (e.target === e.currentTarget) handleClose();
    }}>
      <div className="sw-viewer-container">
        <div className="sw-viewer-header">
          <div className="sw-viewer-header-left">
            <div className="sw-viewer-live-badge">
              <span className="sw-viewer-dot" />
              <span>LIVE</span>
            </div>
            <span className="sw-viewer-title">{post?.title || "Live Stream"}</span>
          </div>
          <div className="sw-viewer-header-right">
            <span className="sw-viewer-count">
              <i className="fa-solid fa-eye" /> {viewerCount}
            </span>
            <button type="button" className="sw-viewer-close" onClick={handleClose}>
              <i className="fa-solid fa-times" />
            </button>
          </div>
        </div>

        <div className="sw-viewer-content">
          <div className="sw-viewer-video-area">
            {isConnecting ? (
              <div className="sw-viewer-video-placeholder">
                <i className="fa-solid fa-spinner fa-spin" />
                <span>Connecting...</span>
              </div>
            ) : error ? (
              <div className="sw-viewer-video-placeholder error">
                <i className="fa-solid fa-exclamation-triangle" />
                <span>{error}</span>
              </div>
            ) : (
              <div className="sw-viewer-main-video">
                <video ref={videoRef} autoPlay playsInline controls />
              </div>
            )}
          </div>

          {/* Live Comments Section */}
          <div className="sw-viewer-comments">
            <div className="sw-viewer-comments-header">
              <i className="fa-solid fa-comments" />
              <span>Live Chat</span>
              <span className="sw-viewer-comments-count">{comments.length}</span>
            </div>

            <div className="sw-viewer-comments-list">
              {comments.length === 0 ? (
                <div className="sw-viewer-comments-empty">
                  <i className="fa-regular fa-comment-dots" />
                  <span>No comments yet. Be the first!</span>
                </div>
              ) : (
                comments.map((c) => (
                  <div
                    key={c.id}
                    className={`sw-viewer-comment ${c._optimistic ? "optimistic" : ""}`}
                  >
                    <span className="sw-viewer-comment-author">@{c.author}</span>
                    <span className="sw-viewer-comment-body">{c.body}</span>
                  </div>
                ))
              )}
              <div ref={commentsEndRef} />
            </div>

            {/* Comment Input */}
            <div className="sw-viewer-comment-input">
              <input
                type="text"
                placeholder={authToken ? "Say something..." : "Log in to comment"}
                value={commentInput}
                onChange={(e) => setCommentInput(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter" && !e.shiftKey) {
                    e.preventDefault();
                    handleSendComment();
                  }
                }}
                disabled={!authToken || commentSending}
              />
              <button
                type="button"
                onClick={handleSendComment}
                disabled={!authToken || !commentInput.trim() || commentSending}
              >
                {commentSending ? (
                  <i className="fa-solid fa-spinner fa-spin" />
                ) : (
                  <i className="fa-solid fa-paper-plane" />
                )}
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
