import {
  apiFetch,
  PresignedUploadResponse,
  sendChatMessage,
  uploadMediaObject,
  type ChatMessage
} from '@/lib/api';
import { compressChatImage, isCompressibleImageFile, readImageDimensions } from '@/lib/chat-image-compress';
import { detectChatMessageType, resolveChatContentType } from '@/lib/chat-media';
import { e2eKindFromMessageType, encryptE2EBlob, type E2EMessagePayload } from '@/lib/e2e-chat';

export interface ChatMediaUploadItem {
  file: File;
  sendAsFile: boolean;
  width?: number;
  height?: number;
}

type EncryptOutgoing = (payload: E2EMessagePayload) => Promise<string>;

export async function uploadChatMediaBatch(params: {
  roomId: string;
  token: string;
  items: ChatMediaUploadItem[];
  caption?: string;
  isE2E: boolean;
  userId?: string;
  peerE2eKey?: string | null;
  encryptOutgoing?: EncryptOutgoing;
}): Promise<ChatMessage[]> {
  const { roomId, token, items, caption, isE2E, userId, peerE2eKey, encryptOutgoing } = params;
  if (!items.length) return [];

  const albumId = crypto.randomUUID();
  const created: ChatMessage[] = [];

  for (let index = 0; index < items.length; index += 1) {
    const item = items[index]!;
    let file = item.file;
    let width = item.width;
    let height = item.height;

    const shouldCompress = isCompressibleImageFile(file) && !item.sendAsFile;
    if (shouldCompress) {
      const compressed = await compressChatImage(file);
      file = compressed.file;
      width = compressed.width ?? width;
      height = compressed.height ?? height;
    } else if (isCompressibleImageFile(file) && (!width || !height)) {
      const dimensions = await readImageDimensions(file);
      width = dimensions.width;
      height = dimensions.height;
    }

    const contentType = resolveChatContentType(file);
    const messageType = item.sendAsFile && isCompressibleImageFile(item.file) ? 'FILE' : detectChatMessageType(file);
    const metadata = {
      fileName: item.file.name,
      fileSize: file.size,
      albumId,
      albumIndex: index,
      albumCount: items.length,
      ...(width ? { width } : {}),
      ...(height ? { height } : {}),
      ...(item.sendAsFile ? { sendAsFile: true } : {})
    };

    let uploadFile = file;
    let uploadContentType = contentType;
    let messageContent: string | undefined =
      index === 0 && caption?.trim()
        ? caption.trim()
        : messageType === 'VIDEO'
          ? 'Видео'
          : messageType === 'VIDEO_NOTE'
            ? 'Видеосообщение'
            : messageType === 'FILE'
              ? item.file.name
              : undefined;
    let isEncrypted = false;

    if (isE2E) {
      if (!userId || !peerE2eKey || !encryptOutgoing) {
        throw new Error('Секретный чат недоступен без ключей E2E у обоих участников');
      }
      const encryptedBuffer = await encryptE2EBlob(userId, peerE2eKey, await file.arrayBuffer());
      uploadFile = new File([encryptedBuffer], `${item.file.name}.lendryenc`, { type: 'application/octet-stream' });
      uploadContentType = 'application/octet-stream';
      messageContent = await encryptOutgoing({
        kind: e2eKindFromMessageType(messageType),
        fileName: item.file.name,
        mimeType: contentType,
        fileSize: file.size,
        text: index === 0 ? caption?.trim() : undefined
      });
      isEncrypted = true;
    }

    const presigned = await apiFetch<PresignedUploadResponse>(
      `/media/chat/${roomId}/media/upload-url`,
      {
        method: 'POST',
        body: JSON.stringify({ contentType: uploadContentType, fileName: uploadFile.name })
      },
      token
    );

    await uploadMediaObject(presigned, uploadFile, uploadContentType);
    const message = await sendChatMessage(
      roomId,
      {
        type: messageType,
        storageKey: presigned.storageKey,
        mimeType: uploadContentType,
        content: messageContent,
        isEncrypted,
        metadataJson: JSON.stringify(isE2E ? { e2e: true, ...metadata } : metadata)
      },
      token
    );
    created.push(message);
  }

  return created;
}
