/* eslint-disable react-hooks/rules-of-hooks */
"use client";

import Container from "@/components/elements/Container";
import useAxios from "@/hooks/useAxios";
import { User } from "@/types/types";
import React, { useState, useEffect, useRef, useCallback } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import {
  getChatSocket,
} from "@/lib/chat/socketClient";
import MessageInput from "@/components/chat/MessageInput";
import GiftInChatModal from "@/components/chat/GiftInChatModal";
import MultiImageModal from "@/components/chat/MultiImageModal";
import MediaPreviewModal from "@/components/chat/MediaPreviewModal";
import ChatActionBar from "@/components/chat/ChatActionBar";
import ChatDeleteBar from "@/components/chat/ChatDeleteBar";
import { useUser } from "@/hooks/useUser";
import ChatMessageList from "@/components/chat/ChatMessageList";
import ChatHeader from "@/components/chat/ChatHeader";
import dynamic from "next/dynamic";
import type { ChatMessage } from "@/components/chat/ChatMessageCard";
import toast from "react-hot-toast";
import { optimizeMediaFile } from "@/lib/media";
import ForwardMessageModal from "@/components/chat/ForwardMessageModal";
import { AnimatePresence } from "framer-motion";
import { useQueryClient } from "@tanstack/react-query";
import { chatThreadQueryKey } from "@/lib/chat/queryKeys";
import { normalizeThreadId, upsertMessageInThreadCache } from "@/lib/chat/threadCache";
import { useStableMessageKeys } from "@/hooks/useStableMessageKeys";
import { getStoredUserId } from "@/lib/auth/session";
import { isViewOnceMediaType } from "@/lib/chat/viewOnce";
import {
  copyTextToClipboard,
  getCopyableMessageText,
} from "@/lib/chat/getCopyableMessageText";
import {
  findPendingMatchForServer,
} from "@/lib/chat/dedupeMessages";
import { useTranslation } from "react-i18next";
import LocalePageShell from "@/components/i18n/LocalePageShell";
import {
  decryptDmContent,
  encryptDmContent,
  E2EE_LOCKED_PREVIEW,
  rememberOutboundPlaintext,
  ensureIdentityKeys,
} from "@/lib/e2ee";

interface ITicketChatProps {
  params: Promise<{ id: string; username: string }>;
}

function normalizeMessage(raw: ChatMessage & { data?: ChatMessage }): ChatMessage {
  const m = (raw as { data?: ChatMessage }).data ?? raw;
  return {
    ...m,
    replyTo: m.replyTo ?? undefined,
  };
}

function TicketChat({ params }: ITicketChatProps) {
  const { t } = useTranslation("common");
  const resolvedParams = React.use(params);
  const { request } = useAxios();
  const router = useRouter();
  const searchParams = useSearchParams();
  const { username, id: chatPartnerId } = resolvedParams;
  const [newMessage, setNewMessage] = useState("");
  const [showGiftModal, setShowGiftModal] = useState(false);
  const [userTwoDetail, setUserTwoDetail] = useState<User>();
  const [pendingImages, setPendingImages] = useState<File[]>([]);
  const [showMultiModal, setShowMultiModal] = useState(false);
  const [pendingMediaPreview, setPendingMediaPreview] = useState<{
    file: File;
    kind: "video" | "file";
  } | null>(null);
  const [pendingMessages, setPendingMessages] = useState<ChatMessage[]>([]);
  const [replyingTo, setReplyingTo] = useState<ChatMessage | null>(null);
  const [forwardMessage, setForwardMessage] = useState<ChatMessage | null>(null);
  const [selectedMessage, setSelectedMessage] = useState<ChatMessage | null>(null);
  const [actionMode, setActionMode] = useState(false);
  const [deleteMode, setDeleteMode] = useState(false);
  const [selectedDeleteIds, setSelectedDeleteIds] = useState<string[]>([]);
  const [deleteLoading, setDeleteLoading] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");
  const [selfDestructSeconds, setSelfDestructSeconds] = useState<number | null>(
    null
  );
  const [viewOnceMedia, setViewOnceMedia] = useState(false);
  const user = useUser();
  const queryClient = useQueryClient();
  const { linkIds, getStableKey } = useStableMessageKeys();
  const [receiverId, setReceiverId] = useState(chatPartnerId);
  const [isTyping, setIsTyping] = useState(false);
  const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const activeReplyRef = useRef<ChatMessage | null>(null);
  const scrollToMessageRef = useRef<(targetId: string) => void>(() => {});

  const handleIncomingMessage = useCallback(
    (msg: ChatMessage) => {
      setPendingMessages((prev) => {
        const match = findPendingMatchForServer(msg, prev);
        if (match) {
          linkIds(match._id, msg._id);
          return prev.filter((m) => m._id !== match._id);
        }
        return prev;
      });
    },
    [linkIds]
  );

  const confirmSentMessage = useCallback(
    (tempId: string, serverMsg: ChatMessage, replyPayload?: ChatMessage["replyTo"]) => {
      const sentMsg: ChatMessage = {
        ...serverMsg,
        status: "sent",
        replyTo: serverMsg.replyTo ?? replyPayload,
      };

      const currentUserId = normalizeThreadId(user?._id ?? getStoredUserId());
      const targetReceiverId = normalizeThreadId(
        userTwoDetail?._id ?? receiverId ?? chatPartnerId
      );

      linkIds(tempId, sentMsg._id);

      if (currentUserId && targetReceiverId) {
        queryClient.setQueryData(
          chatThreadQueryKey(currentUserId, targetReceiverId),
          (oldData) => upsertMessageInThreadCache(oldData, sentMsg)
        );
      }

      setPendingMessages((prev) => prev.filter((m) => m._id !== tempId));
    },
    [user?._id, userTwoDetail?._id, receiverId, chatPartnerId, linkIds, queryClient]
  );

  const handleTyping = useCallback(() => {
    const socket = getChatSocket();
    if (!socket || !user?._id || !receiverId) return;
    socket.emit("typing", {
      senderId: user._id,
      receiverId,
    });
    if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
    typingTimeoutRef.current = setTimeout(() => {
      getChatSocket()?.emit("stopTyping", {
        senderId: user._id,
        receiverId,
      });
    }, 2000);
  }, [user?._id, receiverId]);

  useEffect(() => {
    const fetchStates = async () => {
      try {
        const response = await request<{ user: User }>(
          "GET",
          `/users/get/web?user_name=${username}&_t=${Date.now()}`
        );
        setUserTwoDetail(response?.user);
      } catch (err) {
        console.error("Error fetching user:", err);
      }
    };
    fetchStates();
  }, [username, request]);

  useEffect(() => {
    setReceiverId(userTwoDetail?._id || chatPartnerId);
  }, [user, userTwoDetail, chatPartnerId]);

  const handleFileSelection = (e: React.ChangeEvent<HTMLInputElement>) => {
    const picked = Array.from(e.target.files || []);
    if (!picked.length) return;
    const MAX_SIZE = 200 * 1024 * 1024;
    const valid = picked.filter((f) => {
      if (f.size > MAX_SIZE) {
        toast.error(t("chats.toast.fileTooLargeNamed", { name: f.name }));
        return false;
      }
      return true;
    });
    if (!valid.length) return;

    const videos = valid.filter((f) => f.type.startsWith("video/"));
    const images = valid.filter((f) => f.type.startsWith("image/"));
    const others = valid.filter(
      (f) => !f.type.startsWith("video/") && !f.type.startsWith("image/")
    );

    if (videos.length === 1 && images.length === 0 && others.length === 0) {
      setPendingMediaPreview({ file: videos[0], kind: "video" });
      return;
    }

    if (others.length === 1 && images.length === 0 && videos.length === 0) {
      setPendingMediaPreview({ file: others[0], kind: "file" });
      return;
    }

    if (images.length) {
      setPendingImages((prev) => [...prev, ...images].slice(0, 10));
      setShowMultiModal(true);
    }
  };

  const handleVoiceUpload = (blob: Blob) => {
    const voiceFile = new File([blob], "voice-message.webm", {
      type: "audio/webm",
    });
    processSendMessage(voiceFile, "voice");
  };

  const handleLocationShare = () => {
    if (!navigator.geolocation) {
      toast.error(t("chats.toast.geolocationUnsupported"));
      return;
    }
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        const locationContent = JSON.stringify({
          lat: pos.coords.latitude,
          lng: pos.coords.longitude,
          label: t("chats.locationLabel"),
        });
        processSendMessage(null, "location", locationContent);
      },
      () => toast.error(t("chats.toast.geolocationDenied"))
    );
  };

  const sendGiftMessage = useCallback(
    (gift: { _id: string; amount: number; message: string | null }) => {
      const content = JSON.stringify({
        sharedGift: {
          giftId: gift._id,
          amount: gift.amount,
          message: gift.message,
        },
      });
      void processSendMessage(null, undefined, content);
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [userTwoDetail, receiverId, chatPartnerId, selfDestructSeconds, viewOnceMedia]
  );

  useEffect(() => {
    const giftId = searchParams.get("giftId");
    if (!giftId) return;
    const giftAmount = Number(searchParams.get("giftAmount") || 0);
    const giftMessage = searchParams.get("giftMessage") || "";
    sendGiftMessage({ _id: giftId, amount: giftAmount, message: giftMessage || null });
    const params = new URLSearchParams(searchParams.toString());
    params.delete("giftId");
    params.delete("giftAmount");
    params.delete("giftMessage");
    const query = params.toString();
    router.replace(`/settings/chats/${username}/${chatPartnerId}${query ? `?${query}` : ""}`);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const sendMessage = () => {
    if (pendingImages.length > 0) {
      void sendAllImages();
      return;
    }
    processSendMessage(null);
  };

  const sendAllImages = async () => {
    const batch = [...pendingImages];
    setShowMultiModal(false);
    setPendingImages([]);
    for (const file of batch) {
      await processSendMessage(file, "image");
    }
  };

  const buildReplyPayload = (source: ChatMessage | null) => {
    if (!source) return undefined;
    return {
      _id: source._id,
      content: source.content?.slice(0, 120) || t("chats.message"),
      senderName:
        source.senderId === user?._id
          ? t("chats.you")
          : `${userTwoDetail?.first_name || ""} ${userTwoDetail?.last_name || ""}`.trim(),
    };
  };

  const processSendMessage = async (
    fileToUpload: File | null,
    fileType?: ChatMessage["fileType"],
    contentOverride?: string
  ) => {
    const replySource = activeReplyRef.current;
    let textContent = contentOverride ?? newMessage;
    if (textContent.trim() === "" && !fileToUpload) return;

    if (userTwoDetail?.blocked_you || userTwoDetail?.is_blocked) {
      toast.error(t("chats.toast.sendBlocked"));
      return;
    }

    const tempId = `temp-${Date.now()}-${Math.random()}`;
    const replyPayload = buildReplyPayload(replySource);

    const currentUserId = normalizeThreadId(user?._id ?? getStoredUserId());
    const targetReceiverId = normalizeThreadId(
      userTwoDetail?._id ?? receiverId ?? chatPartnerId
    );

    const applyViewOnce =
      viewOnceMedia && fileType && isViewOnceMediaType(fileType);

    const optimisticMsg: ChatMessage = {
      _id: tempId,
      content: textContent,
      senderId: currentUserId,
      receiverId: targetReceiverId,
      createdAt: new Date().toISOString(),
      selfDestructSeconds: selfDestructSeconds || undefined,
      status: "pending",
      file: fileToUpload ? URL.createObjectURL(fileToUpload) : "",
      fileType: fileType,
      replyTo: replyPayload,
      viewOnce: applyViewOnce || undefined,
    };

    setPendingMessages((prev) => [...prev, optimisticMsg]);
    setNewMessage("");

    let fileForUpload = fileToUpload;
    if (fileToUpload && fileType !== "location") {
      try {
        toast.loading(t("chats.toast.optimizingFile"), { id: "media-opt" });
        fileForUpload = await optimizeMediaFile(fileToUpload);
        toast.dismiss("media-opt");
      } catch {
        toast.dismiss("media-opt");
      }
    }

    const isFileUpload = fileForUpload && fileType !== "location";

    try {
      let sendContent = textContent;
      try {
        await ensureIdentityKeys(currentUserId);
        const encrypted = await encryptDmContent(
          currentUserId,
          targetReceiverId,
          textContent
        );
        if (encrypted) sendContent = encrypted;
      } catch {
        /* fallback plaintext if peer has no key yet */
      }

      let messagePayload: Record<string, unknown> = {
        content: sendContent,
        receiverId: targetReceiverId,
      };

      if (replySource?._id && !replySource._id.startsWith("temp")) {
        messagePayload.replyToId = replySource._id;
      }
      if (selfDestructSeconds) {
        messagePayload.selfDestructSeconds = selfDestructSeconds;
      }
      if (fileType) {
        messagePayload.fileType = fileType;
      }
      if (applyViewOnce) {
        messagePayload.viewOnce = true;
      }

      let response: ChatMessage | { data: ChatMessage };

      if (isFileUpload) {
        const formData = new FormData();
        for (const key in messagePayload) {
          formData.append(key, String(messagePayload[key]));
        }
        formData.append("file", fileForUpload);

        response = await request<ChatMessage | { data: ChatMessage }>(
          "post",
          "/chat/file",
          formData
        );
      } else {
        response = await request<ChatMessage | { data: ChatMessage }>(
          "POST",
          "/chat",
          messagePayload
        );
      }

      const serverMsg = normalizeMessage(response as ChatMessage);
      // همیشه متن اصلی خودمان را نگه دار — اگر decrypt fail شود نباید «رمزنگاری‌شده» ببینیم
      if (sendContent && sendContent !== textContent) {
        rememberOutboundPlaintext(sendContent, textContent);
      }
      if (serverMsg.content && serverMsg.content !== textContent) {
        rememberOutboundPlaintext(String(serverMsg.content), textContent);
      }
      try {
        const plain = await decryptDmContent(
          currentUserId,
          targetReceiverId,
          serverMsg.content || textContent
        );
        serverMsg.content =
          !plain || plain === E2EE_LOCKED_PREVIEW ? textContent : plain;
      } catch {
        serverMsg.content = textContent;
      }
      confirmSentMessage(tempId, serverMsg, replyPayload);
      void queryClient.invalidateQueries({ queryKey: ["messages"] });
    } catch (error) {
      console.error("Error sending message:", error);
      setPendingMessages((prev) => prev.filter((m) => m._id !== tempId));
      toast.error(t("chats.toast.sendFailedDot"));
      return;
    }

    setReplyingTo(null);
    activeReplyRef.current = null;
    setSelfDestructSeconds(null);
    if (applyViewOnce) setViewOnceMedia(false);
  };

  const handleExpirePending = useCallback((ids: string[]) => {
    setPendingMessages((prev) => prev.filter((m) => !ids.includes(m._id)));
  }, []);

  const openActionFor = (msg: ChatMessage) => {
    setSelectedMessage(msg);
    setActionMode(true);
  };

  const closeActionMode = () => {
    setActionMode(false);
    setSelectedMessage(null);
  };

  const startReplyFor = useCallback((msg: ChatMessage) => {
    setReplyingTo(msg);
    activeReplyRef.current = msg;
    closeActionMode();
  }, []);

  const startReply = () => {
    if (!selectedMessage) return;
    startReplyFor(selectedMessage);
  };

  const startForward = () => {
    if (!selectedMessage) return;
    setForwardMessage(selectedMessage);
    closeActionMode();
  };

  const copySelectedMessage = async () => {
    if (!selectedMessage) return;
    const text = getCopyableMessageText(selectedMessage);
    if (!text) {
      toast.error(t("chats.toast.copyEmpty"));
      return;
    }

    const copied = await copyTextToClipboard(text);
    if (copied) {
      toast.success(t("chats.toast.copySuccess"));
      closeActionMode();
      return;
    }

    toast.error(t("chats.toast.copyFailed"));
  };

  const reactToMessage = async (emoji: string) => {
    if (!selectedMessage?._id || selectedMessage._id.startsWith("temp-")) return;
    const messageId = selectedMessage._id;
    const currentUserId = normalizeThreadId(user?._id ?? getStoredUserId());
    const targetReceiverId = normalizeThreadId(
      userTwoDetail?._id ?? receiverId ?? chatPartnerId
    );

    const toggleReaction = (
      reactions: ChatMessage["reactions"] = []
    ): ChatMessage["reactions"] => {
      const list = [...(reactions ?? [])];
      const idx = list.findIndex((r) => String(r.userId) === currentUserId);
      if (idx >= 0 && list[idx].emoji === emoji) {
        list.splice(idx, 1);
      } else if (idx >= 0) {
        list[idx] = { userId: currentUserId, emoji };
      } else {
        list.push({ userId: currentUserId, emoji });
      }
      return list;
    };

    const optimisticReactions = toggleReaction(selectedMessage.reactions);
    if (currentUserId && targetReceiverId) {
      queryClient.setQueryData(
        chatThreadQueryKey(currentUserId, targetReceiverId),
        (oldData) => {
          if (!oldData) return oldData;
          return {
            ...oldData,
            pages: oldData.pages.map((page) => ({
              ...page,
              messages: page.messages.map((m) =>
                m._id === messageId
                  ? { ...m, reactions: optimisticReactions }
                  : m
              ),
            })),
          };
        }
      );
    }

    try {
      const response = await request<{ data?: ChatMessage }>(
        "POST",
        "/chat/reaction",
        {
          messageId,
          emoji,
          receiverId: targetReceiverId,
        }
      );
      const updated = response?.data;
      if (updated && currentUserId && targetReceiverId) {
        queryClient.setQueryData(
          chatThreadQueryKey(currentUserId, targetReceiverId),
          (oldData) => upsertMessageInThreadCache(oldData, updated)
        );
      }
      closeActionMode();
    } catch {
      if (currentUserId && targetReceiverId) {
        queryClient.setQueryData(
          chatThreadQueryKey(currentUserId, targetReceiverId),
          (oldData) => {
            if (!oldData) return oldData;
            return {
              ...oldData,
              pages: oldData.pages.map((page) => ({
                ...page,
                messages: page.messages.map((m) =>
                  m._id === messageId
                    ? { ...m, reactions: selectedMessage.reactions }
                    : m
                ),
              })),
            };
          }
        );
      }
      toast.error(t("chats.toast.reactFailed"));
    }
  };

  const handleBlockChange = (blocked?: boolean) => {
    if (typeof blocked === "boolean") {
      setUserTwoDetail((prev) =>
        prev ? { ...prev, is_blocked: blocked } : prev
      );
    }
    void request<{ user: User }>(
      "GET",
      `/users/get/web?user_name=${username}&_t=${Date.now()}`
    ).then((res) => {
      if (res?.user) setUserTwoDetail(res.user);
    });
  };

  const startDeleteMode = () => {
    closeActionMode();
    setSearchQuery("");
    setDeleteMode(true);
    setSelectedDeleteIds([]);
  };

  const cancelDeleteMode = () => {
    setDeleteMode(false);
    setSelectedDeleteIds([]);
  };

  const toggleDeleteSelect = (msg: ChatMessage) => {
    setSelectedDeleteIds((prev) =>
      prev.includes(msg._id)
        ? prev.filter((id) => id !== msg._id)
        : [...prev, msg._id]
    );
  };

  const confirmDeleteMessages = async () => {
    if (!selectedDeleteIds.length || !user?._id) return;
    setDeleteLoading(true);
    try {
      const response = await request<{ deletedIds: string[]; message?: string }>(
        "DELETE",
        "/chat",
        { messageIds: selectedDeleteIds }
      );
      const deleted = new Set(response?.deletedIds || []);
      setPendingMessages((prev) => prev.filter((m) => !deleted.has(m._id)));
      queryClient.setQueryData(
        chatThreadQueryKey(
          normalizeThreadId(user._id),
          normalizeThreadId(userTwoDetail?._id ?? receiverId ?? chatPartnerId)
        ),
        (oldData: { pages: { messages: ChatMessage[] }[] } | undefined) => {
          if (!oldData) return oldData;
          return {
            ...oldData,
            pages: oldData.pages.map((page) => ({
              ...page,
              messages: page.messages.filter((m) => !deleted.has(m._id)),
            })),
          };
        }
      );
      toast.success(response?.message || t("chats.toast.messagesDeleted"));
      cancelDeleteMode();
    } catch {
      toast.error(t("chats.toast.deleteMessagesFailed"));
    } finally {
      setDeleteLoading(false);
    }
  };

  return (
    <LocalePageShell>
    <Container className="chat-page-bg flex h-[100dvh] max-h-[100dvh] flex-col overflow-hidden !px-0">
      <ChatHeader
        user={userTwoDetail}
        searchQuery={searchQuery}
        onSearchChange={setSearchQuery}
        onBlockChange={handleBlockChange}
        onStartDeleteMode={startDeleteMode}
        deleteMode={deleteMode}
      />
      <ChatMessageList
          chatPartnerId={chatPartnerId}
          getStableKey={getStableKey}
          pendingMessages={pendingMessages}
          userDetail={user as User}
          userTwoDetail={userTwoDetail}
          isTyping={isTyping}
          onTypingChange={setIsTyping}
          searchQuery={searchQuery}
          selectedMessageId={selectedMessage?._id}
          onBubbleClick={openActionFor}
          onSwipeReply={startReplyFor}
          actionMode={actionMode}
          onDismissAction={closeActionMode}
          deleteMode={deleteMode}
          selectedDeleteIds={selectedDeleteIds}
          onToggleDeleteSelect={toggleDeleteSelect}
          onExpirePending={handleExpirePending}
          onIncomingMessage={handleIncomingMessage}
          onScrollToMessageReady={(fn) => {
            scrollToMessageRef.current = fn;
          }}
          extraBottomRem={
            (replyingTo ? 2.75 : 0) +
            (selfDestructSeconds != null ? 2 : 0) +
            (viewOnceMedia ? 2 : 0)
          }
      />

      <AnimatePresence mode="wait">
        {deleteMode ? (
          <ChatDeleteBar
            key="delete"
            selectedCount={selectedDeleteIds.length}
            onDelete={confirmDeleteMessages}
            onCancel={cancelDeleteMode}
            loading={deleteLoading}
          />
        ) : actionMode ? (
          <ChatActionBar
            key="actions"
            onReply={startReply}
            onForward={startForward}
            onCopy={copySelectedMessage}
            onCancel={closeActionMode}
            onReact={reactToMessage}
          />
        ) : (
          <MessageInput
            key="input"
            newMessage={newMessage}
            setNewMessage={setNewMessage}
            sendMessage={sendMessage}
            handleFileSelection={handleFileSelection}
            handleVoiceUpload={handleVoiceUpload}
            onLocationShare={handleLocationShare}
            onTyping={handleTyping}
            isChatThread
            blocked_you={userTwoDetail?.blocked_you || userTwoDetail?.is_blocked}
            replyingTo={replyingTo}
            onCancelReply={() => {
              setReplyingTo(null);
              activeReplyRef.current = null;
            }}
            onReplyPreviewClick={() => {
              if (replyingTo?._id) scrollToMessageRef.current(replyingTo._id);
            }}
            replyLabel={
              replyingTo
                ? replyingTo.content?.slice(0, 80) || t("chats.message")
                : undefined
            }
            selfDestructSeconds={selfDestructSeconds}
            onSelfDestructChange={setSelfDestructSeconds}
            viewOnceMedia={viewOnceMedia}
            onViewOnceChange={setViewOnceMedia}
            onGiftClick={() => setShowGiftModal(true)}
          />
        )}
      </AnimatePresence>

      <GiftInChatModal
        open={showGiftModal}
        onClose={() => setShowGiftModal(false)}
        receiverId={String(userTwoDetail?._id ?? receiverId ?? chatPartnerId)}
        returnPath={`/settings/chats/${username}/${chatPartnerId}`}
        onWalletGiftSent={sendGiftMessage}
      />

      <MultiImageModal
        isOpen={showMultiModal}
        files={pendingImages}
        onRemove={(i) =>
          setPendingImages((prev) => {
            const next = prev.filter((_, idx) => idx !== i);
            if (next.length === 0) setShowMultiModal(false);
            return next;
          })
        }
        onCancel={() => {
          setPendingImages([]);
          setShowMultiModal(false);
        }}
        onConfirm={sendAllImages}
        viewOnceMedia={viewOnceMedia}
        onViewOnceChange={setViewOnceMedia}
        selfDestructSeconds={selfDestructSeconds}
        onSelfDestructChange={setSelfDestructSeconds}
      />
      <MediaPreviewModal
        isOpen={!!pendingMediaPreview}
        file={pendingMediaPreview?.file ?? null}
        kind={pendingMediaPreview?.kind ?? "file"}
        onCancel={() => setPendingMediaPreview(null)}
        onConfirm={() => {
          if (!pendingMediaPreview) return;
          const { file, kind } = pendingMediaPreview;
          setPendingMediaPreview(null);
          void processSendMessage(file, kind === "video" ? "video" : "file");
        }}
        viewOnceMedia={viewOnceMedia}
        onViewOnceChange={setViewOnceMedia}
        selfDestructSeconds={selfDestructSeconds}
        onSelfDestructChange={setSelfDestructSeconds}
      />
      {forwardMessage && user?._id && (
        <ForwardMessageModal
          open={!!forwardMessage}
          onClose={() => setForwardMessage(null)}
          message={forwardMessage}
          currentUserId={user._id}
          currentReceiverId={receiverId}
        />
      )}
    </Container>
    </LocalePageShell>
  );
}

export default dynamic(() => Promise.resolve(TicketChat), { ssr: false });
