import IMAGES from "@/constants/images";
import type {
  ChatConversation,
  ChatMessage,
  ChatParticipant,
  InboxListItem,
} from "@/types/chat";

export function getConversationId(
  conversation: ChatConversation | null | undefined
): string | null {
  if (!conversation) return null;
  return conversation._id ?? conversation.id ?? null;
}

export function getOtherParticipant(
  conversation: ChatConversation | null | undefined,
  currentUserId: string
): ChatParticipant | null {
  if (!conversation?.participants?.length || !currentUserId) return null;
  return (
    conversation.participants.find((p) => p._id && p._id !== currentUserId) ??
    null
  );
}

export function getParticipantName(participant?: ChatParticipant | null): string {
  if (!participant) return "Unknown";
  const name = [participant.firstname, participant.lastname]
    .filter(Boolean)
    .join(" ")
    .trim();
  return name || participant.email || "Unknown";
}

export function getParticipantImage(participant?: ChatParticipant | null): string {
  const image = participant?.image?.trim();
  if (image) return image;
  return IMAGES.user02Image;
}

export function formatChatTime(iso?: string | null): string {
  if (!iso) return "";
  return new Date(iso).toLocaleString("en-US", {
    hour: "2-digit",
    minute: "2-digit",
  });
}

export function getLastMessagePreview(message: ChatMessage): string {
  if (message.isDeleted) return "Message deleted";
  if (message.attachments?.length) {
    const img = message.attachments.some((a) => a.type === "image");
    const vid = message.attachments.some((a) => a.type === "video");
    if (img) return "Photo";
    if (vid) return "Video";
    return "Attachment";
  }
  return message.content?.trim() || "";
}

export function conversationToInboxItem(
  conversation: ChatConversation,
  adminId: string
): InboxListItem {
  const conversationId = getConversationId(conversation) ?? "";
  const peer = getOtherParticipant(conversation, adminId);
  const last = conversation.lastMessage;
  const sortTimestamp =
    last?.createdAt ?? conversation.lastMessageTime ?? "";

  return {
    id: peer?._id ?? "",
    conversationId,
    peer: peer ?? { _id: "" },
    name: getParticipantName(peer),
    image: getParticipantImage(peer),
    lastMessage: last ? getLastMessagePreview(last) : "No messages yet",
    time: formatChatTime(sortTimestamp),
    sortTimestamp,
    unreadCount: conversation.unreadCount ?? 0,
    isOnline: Boolean(peer?.is_online),
    isTyping: false,
  };
}

export function isConversationBlocked(
  conversation: ChatConversation | null | undefined
): boolean {
  if (!conversation) return false;
  return Boolean(
    conversation.isBlockedByBoth ||
      conversation.isBlockedByMe ||
      conversation.isBlockedByOther
  );
}

export function dedupeMessages(messages: ChatMessage[]): ChatMessage[] {
  const map = new Map<string, ChatMessage>();
  messages.forEach((m) => {
    const key = m._id || m.tempId || "";
    if (key) map.set(key, m);
  });
  return Array.from(map.values()).sort(
    (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
  );
}

const IMAGE_EXT = /\.(jpe?g|png|gif|webp|bmp|svg|heic|heif)$/i;
const VIDEO_EXT = /\.(mp4|webm|mov|m4v|avi|mkv)$/i;

export function getAttachmentFileKey(file: File): string {
  return `${file.name}-${file.size}-${file.lastModified}`;
}

export function isImageAttachment(file: File): boolean {
  return file.type.startsWith("image/") || IMAGE_EXT.test(file.name);
}

export function isVideoAttachment(file: File): boolean {
  return file.type.startsWith("video/") || VIDEO_EXT.test(file.name);
}

function isPreviewableAttachment(file: File): boolean {
  return isImageAttachment(file) || isVideoAttachment(file);
}

function readFileAsDataUrl(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      if (typeof reader.result === "string") resolve(reader.result);
      else reject(new Error("Could not read file preview."));
    };
    reader.onerror = () => reject(reader.error);
    reader.readAsDataURL(file);
  });
}

export async function buildAttachmentPreviews(
  files: File[]
): Promise<Record<string, string>> {
  const previews: Record<string, string> = {};
  await Promise.all(
    files.map(async (file) => {
      if (!isPreviewableAttachment(file)) return;
      const key = getAttachmentFileKey(file);
      previews[key] = await readFileAsDataUrl(file);
    })
  );
  return previews;
}
