import type { ChatMessage } from '@/lib/api'; import { emojiIdToNative, resolveNativeEmojiContent } from '@/lib/emoji-native-map'; export const QUICK_REACTIONS = ['👍', '❤️', '😂', '😮', '😢', '🙏', '🔥', '👏'] as const; export interface ForwardedFromMeta { messageId: string; roomId: string; senderId: string; senderName: string; type: string; content?: string; } export function parseForwardedFrom(metadataJson?: string): ForwardedFromMeta | null { if (!metadataJson) return null; try { const meta = JSON.parse(metadataJson) as { forwardedFrom?: ForwardedFromMeta }; const forwarded = meta.forwardedFrom; return forwarded?.messageId ? forwarded : null; } catch { return null; } } export function getMessageCopyText(message: ChatMessage, visibleText?: string) { if (message.isDeleted) return ''; if (visibleText?.trim()) return resolveNativeEmojiContent(visibleText.trim()); if (message.content?.trim()) { if (message.type === 'EMOJI') { return emojiIdToNative(message.content.trim()) ?? message.content.trim(); } return resolveNativeEmojiContent(message.content.trim()); } if (message.type === 'POLL' && message.poll) return message.poll.question; return ''; } function looksLikeEncryptedPayload(content?: string | null) { if (!content?.trim().startsWith('{')) return false; try { const parsed = JSON.parse(content) as { v?: unknown; ciphertext?: unknown; kind?: unknown }; return typeof parsed === 'object' && parsed !== null && ('v' in parsed || 'ciphertext' in parsed || 'kind' in parsed); } catch { return false; } } export function getMessagePreviewText(message: ChatMessage, visibleText?: string) { if (message.type === 'SYSTEM') { return resolveNativeEmojiContent(message.content?.trim() ?? 'Системное сообщение'); } if (message.type === 'POLL' && message.poll) { return `📊 Опрос: ${message.poll.question}`; } const text = getMessageCopyText(message, visibleText); if (text && !looksLikeEncryptedPayload(text)) return text; if (message.type === 'IMAGE') return '📷 Фото'; if (message.type === 'VIDEO') return '🎬 Видео'; if (message.type === 'VIDEO_NOTE') return '⭕ Кружок'; if (message.type === 'LOCATION') return '📍 Геопозиция'; if (message.type === 'VOICE') return '🎤 Голосовое'; if (message.type === 'AUDIO') return '🎵 Аудио'; if (message.type === 'FILE') return '📄 Файл'; if (message.isEncrypted) return '🔒 Зашифрованное сообщение'; return 'Сообщение'; } export function getChatListPreviewText(message?: ChatMessage | null, fallback = '') { if (!message || message.isDeleted) return fallback; return getMessagePreviewText(message); } export function isSystemMessage(message: ChatMessage) { return message.type === 'SYSTEM'; } export function isSelectableMessage(message: ChatMessage) { return !message.isDeleted && !isSystemMessage(message); } export function isChatInteractiveTarget(target: EventTarget | null) { if (!(target instanceof HTMLElement)) return false; return Boolean( target.closest('button, a, input, textarea, select, label, [contenteditable="true"], [data-chat-interactive="true"]') ); } export function canEditMessage(message: ChatMessage, userId?: string, isE2E?: boolean) { return ( Boolean(userId && message.senderId === userId) && !message.isDeleted && !isSystemMessage(message) && !message.isEncrypted && !isE2E && (message.type === 'TEXT' || message.type === 'EMOJI') ); } export function canDeleteMessage(message: ChatMessage, userId?: string) { return Boolean(userId && message.senderId === userId && !message.isDeleted && !isSystemMessage(message)); }