"use client";

import Image from "next/image";
import { useState, useEffect, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
import Link from "next/link";
import { User } from "@/types/types";
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
import ReadReceipt from "./ReadReceipt";
import VoiceMessagePlayer from "./VoiceMessagePlayer";
import FileMessageBubble from "./FileMessageBubble";
import VideoMessageBubble from "./VideoMessageBubble";
import LocationMessageBubble, {
  parseLocationContent,
} from "./LocationMessageBubble";
import { detectChatFileType } from "@/lib/chat/detectFileType";
import { formatBubbleTime } from "@/lib/chat/formatMessageTime";
import { useLongPress } from "@/hooks/useLongPress";
import { useSwipeToReply } from "@/hooks/useSwipeToReply";
import BoldIcon from "@/components/ui/BoldIcon";
import ChatBoldIcon from "./ChatBoldIcon";
import { cn } from "@/lib/utils";
import {
  formatCountdown,
  getRemainingSeconds,
} from "@/lib/chat/timedMessages";
import { useViewOnceMedia } from "@/hooks/useViewOnceMedia";
import ViewOnceMediaBubble from "./ViewOnceMediaBubble";
import { isViewOnceMediaType } from "@/lib/chat/viewOnce";
import toast from "react-hot-toast";
import {
  type BubbleGroupPosition,
  getBubbleRadius,
  getMessageRowSpacing,
} from "@/lib/chat/messageGrouping";

function ViewOnceBadge() {
  return (
    <span className="absolute left-2 top-2 z-[2] flex h-5 min-w-[20px] items-center justify-center rounded-full bg-[#ff9500] px-1.5 text-[10px] font-bold text-white shadow">
      ۱
    </span>
  );
}

function TimedBadge({ expiresAt }: { expiresAt: string }) {
  const [remaining, setRemaining] = useState(() =>
    getRemainingSeconds(expiresAt)
  );

  useEffect(() => {
    const tick = () => setRemaining(getRemainingSeconds(expiresAt));
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, [expiresAt]);

  if (remaining == null || remaining <= 0) return null;

  return (
    <span
      className="chat-timer-badge-glass mr-1"
      title="پیام زماندار"
    >
      <ChatBoldIcon name="timer" size={10} className="inline-block align-middle" />
      {formatCountdown(remaining)}
    </span>
  );
}

export interface ChatMessage {
  _id: string;
  content: string;
  senderId: string;
  receiverId?: string;
  createdAt: string;
  createdAtIso?: string;
  expiresAt?: string;
  viewOnce?: boolean;
  viewOnceLocked?: boolean;
  viewOnceExpired?: boolean;
  file?: string;
  fileType?: "image" | "video" | "file" | "voice" | "location";
  status?: "pending" | "sent" | "seen";
  replyTo?: {
    _id: string;
    content: string;
    senderName?: string;
  };
  forwardedFrom?: {
    userId: string;
    userName: string;
    displayName: string;
  };
}

interface ChatMessageCardProps {
  message: ChatMessage;
  userDetail: User | undefined;
  groupPosition?: BubbleGroupPosition;
  isGroupedWithPrev?: boolean;
  showAvatar?: boolean;
  partnerAvatar?: string;
  isNew?: boolean;
  selected?: boolean;
  onBubbleClick?: (message: ChatMessage) => void;
  onSwipeReply?: (message: ChatMessage) => void;
  deleteMode?: boolean;
  selectedForDelete?: boolean;
  onToggleDeleteSelect?: (message: ChatMessage) => void;
  onScrollToReply?: (messageId: string) => void;
  highlighted?: boolean;
  registerRef?: (id: string, el: HTMLDivElement | null) => void;
}

const LONG_PRESS_MS = 2000;

function parseForwarded(content: string): ChatMessage["forwardedFrom"] | null {
  try {
    const line = content.split("\n")[0];
    const j = JSON.parse(line);
    return j.forwardedFrom ?? null;
  } catch {
    return null;
  }
}

function isEmojiOnly(text: string): boolean {
  const stripped = text.trim();
  if (!stripped) return false;
  return !/[\p{L}\p{N}]/u.test(stripped);
}

const ChatMessageCard = ({
  message,
  userDetail,
  groupPosition = "single",
  isGroupedWithPrev = false,
  showAvatar = false,
  partnerAvatar,
  isNew = false,
  selected = false,
  onBubbleClick,
  onSwipeReply,
  deleteMode = false,
  selectedForDelete = false,
  onToggleDeleteSelect,
  onScrollToReply,
  highlighted = false,
  registerRef,
}: ChatMessageCardProps) => {
  const currentUserId = String(userDetail?._id ?? "");
  const isSender =
    !!currentUserId && String(message.senderId) === currentUserId;
  const [preview, setPreview] = useState<string | null>(null);
  const [viewOncePreview, setViewOncePreview] = useState<{
    url: string;
    type: "image" | "video";
  } | null>(null);
  const [viewOnceVoiceUrl, setViewOnceVoiceUrl] = useState<string | null>(null);
  const { openViewOnce, completeViewOnce } = useViewOnceMedia();
  const canSelectForDelete = deleteMode && isSender && !message._id.startsWith("temp-");
  const swipeEnabled = !deleteMode && !!onSwipeReply;

  const handleOpenActions = useCallback(() => {
    onBubbleClick?.(message);
  }, [message, onBubbleClick]);

  const handleSwipeReply = useCallback(() => {
    onSwipeReply?.(message);
  }, [message, onSwipeReply]);

  const { pressing, shouldBlockClick, cancelPress, handlers: longPressHandlers } =
    useLongPress(handleOpenActions, { delay: LONG_PRESS_MS });

  const { dragProps, replyOpacity, replyScale } = useSwipeToReply(
    handleSwipeReply,
    swipeEnabled,
    isSender ? "left" : "right"
  );

  const swipeDragStart =
    swipeEnabled && "onDragStart" in dragProps ? dragProps.onDragStart : undefined;
  const restDragProps = swipeEnabled
    ? (() => {
        const { onDragStart: _, ...rest } = dragProps;
        return rest;
      })()
    : {};

  const toggleDeleteSelection = () => {
    if (canSelectForDelete) onToggleDeleteSelect?.(message);
  };

  const openPreview = (url: string) => {
    if (deleteMode) {
      toggleDeleteSelection();
      return;
    }
    if (shouldBlockClick()) return;
    setPreview(url);
  };

  const bubbleHandlers = deleteMode
    ? { onClick: toggleDeleteSelection }
    : longPressHandlers;

  const handleDragStart = () => {
    cancelPress();
    swipeDragStart?.();
  };

  const forwarded =
    message.forwardedFrom || parseForwarded(message.content || "");
  const locationData = parseLocationContent(message.content);
  const hasLocation = message.fileType === "location" || !!locationData;

  if (
    !message.content &&
    !message.file &&
    !hasLocation &&
    !(message.viewOnce && isViewOnceMediaType(message.fileType))
  ) {
    return null;
  }

  const fileUrl = message.file?.startsWith("blob:")
    ? message.file
    : message.file
      ? IMAGE_BASE_URL + message.file
      : "";

  const fileType = hasLocation
    ? "location"
    : detectChatFileType(message.file || "", message.fileType);

  const textContent =
    message.content &&
    !parseLocationContent(message.content) &&
    !forwarded
      ? message.content.replace(/^\{.*\}\n?/, "").trim()
      : message.content?.replace(/^\{.*\}\n?/, "").trim() || "";

  const showTextBubble =
    textContent &&
    fileType !== "file" &&
    fileType !== "location" &&
    (!message.file || (fileType === "image" && textContent));

  const emojiOnly = showTextBubble && !message.file && isEmojiOnly(textContent);
  const borderRadius = getBubbleRadius(isSender, groupPosition);
  const rowSpacing = getMessageRowSpacing(groupPosition, isGroupedWithPrev);
  const timeLabel = formatBubbleTime(message.createdAt);
  const isPending = message.status === "pending";

  const isViewOnce =
    Boolean(message.viewOnce) && isViewOnceMediaType(fileType);
  const showViewOnceLocked =
    isViewOnce &&
    !isSender &&
    (message.viewOnceLocked || message.viewOnceExpired) &&
    !viewOnceVoiceUrl;

  const finishViewOnce = useCallback(async () => {
    setViewOncePreview(null);
    setViewOnceVoiceUrl(null);
    if (message._id.startsWith("temp")) return;
    try {
      await completeViewOnce(message._id);
    } catch {
      toast.error("حذف پیام یک‌بارمصرف ناموفق بود");
    }
  }, [completeViewOnce, message._id]);

  const handleViewOnceOpen = useCallback(async () => {
    if (message._id.startsWith("temp")) return;
    try {
      const { url, fileType: openedType } = await openViewOnce(message._id);
      if (openedType === "voice") {
        setViewOnceVoiceUrl(url);
      } else if (openedType === "video") {
        setViewOncePreview({ url, type: "video" });
      } else {
        setViewOncePreview({ url, type: "image" });
      }
    } catch {
      toast.error("باز کردن پیام یک‌بارمصرف ممکن نیست");
    }
  }, [message._id, openViewOnce]);

  const TimeInline = () => (
    <span className="message-time-inline">
      {timeLabel}
      {message.expiresAt && <TimedBadge expiresAt={message.expiresAt} />}
      {isSender && (
        <span className="mr-1 inline-flex align-middle">
          <ReadReceipt status={message.status} />
        </span>
      )}
    </span>
  );

  const TimeBelow = () => (
    <span
      className={cn(
        "message-time-below mt-0.5 block text-[10px] tabular-nums",
        isSender ? "text-left" : "text-right"
      )}
    >
      {timeLabel}
      {message.expiresAt && <TimedBadge expiresAt={message.expiresAt} />}
      {isSender && (
        <span className="mr-1 inline-flex">
          <ReadReceipt status={message.status} />
        </span>
      )}
    </span>
  );

  const bubbleStyle = {
    borderRadius,
    ...(isSender
      ? {}
      : {}),
  };

  return (
    <>
      <motion.div
        ref={(el) => registerRef?.(message._id, el)}
        data-message-id={message._id}
        initial={
          isNew
            ? { opacity: 0, y: 8, scale: 0.98 }
            : false
        }
        animate={{
          opacity: isPending ? 0.82 : 1,
          y: 0,
          scale: 1,
        }}
        transition={{
          duration: 0.24,
          ease: [0.25, 0.46, 0.45, 0.94],
        }}
        className={cn(
          "relative flex w-full gap-2",
          isSender ? "justify-end pl-10" : "justify-start pr-10",
          rowSpacing,
          deleteMode && !isSender && "opacity-60",
          selected && "relative z-[2]",
          highlighted && "chat-message-highlight relative z-[2]"
        )}
        dir="rtl"
      >
        {canSelectForDelete && (
          <button
            type="button"
            onClick={toggleDeleteSelection}
            className={cn(
              "gentle-transition order-first flex h-6 w-6 shrink-0 items-center justify-center self-end rounded-full border-2",
              selectedForDelete
                ? "border-[#0095f6] bg-[#0095f6] text-white"
                : "border-neutral-400 bg-transparent"
            )}
            aria-label={selectedForDelete ? "لغو انتخاب" : "انتخاب پیام"}
          >
            {selectedForDelete && <BoldIcon name="tick-circle" size={14} tinted className="text-white" />}
          </button>
        )}

        <div
          className={cn(
            "relative flex max-w-[min(78%,280px)] flex-col sm:max-w-[min(75%,320px)]",
            isSender ? "items-end" : "items-start"
          )}
        >
          {forwarded && (
            <Link
              href={`/users/${forwarded.userName}`}
              className="mb-0.5 text-[11px] font-semibold text-[#0095f6]"
              onClick={(e) => e.stopPropagation()}
            >
              {forwarded.displayName}
            </Link>
          )}

          {message.replyTo && (
            <button
              type="button"
              onClick={() => {
                if (message.replyTo?._id) onScrollToReply?.(message.replyTo._id);
              }}
              className="gentle-transition mb-1 max-w-full cursor-pointer rounded-lg border-r-2 border-[#0095f6] bg-black/5 px-2 py-1 text-right text-[11px] opacity-90 hover:bg-[#0095f6]/10 active:scale-[0.98] dark:bg-white/10"
            >
              <span className="font-semibold text-[#0095f6]">
                {message.replyTo.senderName}
              </span>
              <p className="truncate">{message.replyTo.content}</p>
            </button>
          )}

          <div className="relative w-full overflow-hidden">
            {swipeEnabled && (
              <motion.div
                aria-hidden
                className={cn(
                  "pointer-events-none absolute inset-y-0 flex w-11 items-center justify-center text-[#0095f6]",
                  isSender ? "right-0" : "left-0"
                )}
                style={{ opacity: replyOpacity, scale: replyScale }}
              >
                <ChatBoldIcon
                  name="reply"
                  size={20}
                  className={cn("text-current", !isSender && "-scale-x-100")}
                />
              </motion.div>
            )}

            <motion.div
              {...(swipeEnabled ? restDragProps : {})}
              onDragStart={swipeEnabled ? handleDragStart : undefined}
              className="relative z-[1] w-full"
            >
              <div
                data-chat-bubble
                {...bubbleHandlers}
                className={cn(
                  "relative select-none text-right outline-none touch-manipulation",
                  canSelectForDelete && "cursor-pointer",
                  (selected || selectedForDelete) &&
                    "rounded-2xl ring-2 ring-[#0095f6]/50",
                  !deleteMode && pressing && "scale-[0.98] opacity-90"
                )}
              >
            {fileType === "image" &&
              (fileUrl || (isViewOnce && !isSender)) &&
              (showViewOnceLocked ? (
                <div style={{ borderRadius }}>
                  <ViewOnceMediaBubble
                    fileType="image"
                    isOutgoing={isSender}
                    expired={Boolean(message.viewOnceExpired)}
                    borderRadius={borderRadius}
                    onOpen={handleViewOnceOpen}
                  />
                  <TimeBelow />
                </div>
              ) : fileUrl ? (
                <div
                  className="relative block overflow-hidden"
                  style={{ borderRadius }}
                  onClick={(e) => {
                    e.stopPropagation();
                    openPreview(fileUrl);
                  }}
                >
                  {isViewOnce && isSender && <ViewOnceBadge />}
                  <div className="relative aspect-[3/4] w-44 sm:w-52">
                    <Image
                      fill
                      src={fileUrl}
                      alt=""
                      className="object-cover"
                      sizes="208px"
                    />
                  </div>
                  <TimeBelow />
                </div>
              ) : null)}

            {fileType === "video" &&
              (fileUrl || (isViewOnce && !isSender)) &&
              (showViewOnceLocked ? (
                <div style={{ borderRadius }}>
                  <ViewOnceMediaBubble
                    fileType="video"
                    isOutgoing={isSender}
                    expired={Boolean(message.viewOnceExpired)}
                    borderRadius={borderRadius}
                    onOpen={handleViewOnceOpen}
                  />
                  <TimeBelow />
                </div>
              ) : fileUrl ? (
                <div
                  className="relative cursor-pointer overflow-hidden"
                  style={{ borderRadius }}
                  onClick={(e) => {
                    e.stopPropagation();
                    openPreview(fileUrl);
                  }}
                >
                  {isViewOnce && isSender && <ViewOnceBadge />}
                  <VideoMessageBubble src={fileUrl} isOutgoing={isSender} />
                  <TimeBelow />
                </div>
              ) : null)}

            {fileType === "voice" &&
              (fileUrl || viewOnceVoiceUrl || (isViewOnce && !isSender)) &&
              (showViewOnceLocked ? (
                <div style={bubbleStyle}>
                  <ViewOnceMediaBubble
                    fileType="voice"
                    isOutgoing={isSender}
                    expired={Boolean(message.viewOnceExpired)}
                    borderRadius={borderRadius}
                    onOpen={handleViewOnceOpen}
                  />
                  <TimeBelow />
                </div>
              ) : viewOnceVoiceUrl ? (
                <div
                  className={isSender ? "chat-bubble-out p-1" : "chat-bubble-in p-1"}
                  style={bubbleStyle}
                >
                  <VoiceMessagePlayer
                    src={viewOnceVoiceUrl}
                    isOutgoing={isSender}
                    autoPlay
                    singlePlay
                    onPlaybackComplete={finishViewOnce}
                  />
                  <TimeBelow />
                </div>
              ) : fileUrl ? (
                <div
                  className={cn(
                    isSender ? "chat-bubble-out p-1" : "chat-bubble-in p-1",
                    isViewOnce && isSender && "relative"
                  )}
                  style={bubbleStyle}
                >
                  {isViewOnce && isSender && <ViewOnceBadge />}
                  <VoiceMessagePlayer src={fileUrl} isOutgoing={isSender} />
                  <TimeBelow />
                </div>
              ) : null)}

            {fileType === "file" && fileUrl && (
              <div style={bubbleStyle} className="overflow-hidden">
                <FileMessageBubble
                  url={fileUrl}
                  fileName={textContent || "فایل"}
                  isOutgoing={isSender}
                />
                <TimeBelow />
              </div>
            )}

            {fileType === "location" && locationData && (
              <div style={bubbleStyle} className="overflow-hidden">
                <LocationMessageBubble location={locationData} isOutgoing={isSender} />
                <TimeBelow />
              </div>
            )}

            {showTextBubble && !message.file && emojiOnly && (
              <p className="px-1 py-0.5 text-[2.5rem] leading-none">{textContent}</p>
            )}

            {showTextBubble && !message.file && !emojiOnly && (
              <div
                className={cn(
                  "chat-text-bubble px-3 py-2 text-[15px] leading-snug",
                  isSender ? "chat-bubble-out" : "chat-bubble-in"
                )}
                style={bubbleStyle}
              >
                <p className="chat-message-text">{textContent}</p>
                <TimeInline />
              </div>
            )}
              </div>
            </motion.div>
          </div>
        </div>

        {!isSender && (
          <div className="flex w-7 shrink-0 items-end self-end">
            {showAvatar && partnerAvatar ? (
              <div className="relative h-7 w-7 overflow-hidden rounded-full bg-neutral-700">
                <Image
                  src={buildStorageUrl(partnerAvatar)}
                  alt=""
                  fill
                  className="object-cover"
                  sizes="28px"
                />
              </div>
            ) : (
              <div className="h-7 w-7" aria-hidden />
            )}
          </div>
        )}
      </motion.div>

      <AnimatePresence>
        {viewOncePreview && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/95"
            onClick={() => void finishViewOnce()}
          >
            <motion.div
              initial={{ scale: 0.9 }}
              animate={{ scale: 1 }}
              className="max-h-[92vh] max-w-[95vw] p-4"
              onClick={(e) => e.stopPropagation()}
            >
              {viewOncePreview.type === "video" ? (
                <video
                  src={viewOncePreview.url}
                  controls
                  autoPlay
                  className="max-h-[88vh] rounded-lg"
                />
              ) : (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={viewOncePreview.url}
                  alt=""
                  className="max-h-[88vh] object-contain"
                />
              )}
            </motion.div>
          </motion.div>
        )}
        {preview && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/90 backdrop-blur-xl"
            onClick={() => setPreview(null)}
          >
            <button
              type="button"
              onClick={() => setPreview(null)}
              className="gentle-transition absolute right-4 top-[calc(1rem+env(safe-area-inset-top))] z-[2] flex h-10 w-10 items-center justify-center rounded-full bg-white/15 text-white backdrop-blur-md active:scale-90"
              aria-label="بستن"
            >
              <BoldIcon name="close-circle" size={24} tinted className="text-white" />
            </button>
            <motion.div
              initial={{ scale: 0.92, opacity: 0.6 }}
              animate={{ scale: 1, opacity: 1 }}
              exit={{ scale: 0.92, opacity: 0 }}
              transition={{ duration: 0.22, ease: [0.25, 0.46, 0.45, 0.94] }}
              className="max-h-[92vh] max-w-[95vw] p-4"
              onClick={(e) => e.stopPropagation()}
            >
              {fileType === "video" ? (
                <video
                  src={preview}
                  controls
                  autoPlay
                  className="max-h-[88vh] rounded-2xl shadow-2xl"
                />
              ) : (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={preview}
                  alt=""
                  className="max-h-[88vh] rounded-2xl object-contain shadow-2xl"
                />
              )}
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
};

export default ChatMessageCard;
