import {
  parseMessagePayload,
  type AttachmentHandle,
  type DecryptedMessage,
} from '@chat-app/shared/chat';
import { describe, expect, it } from 'vitest';

import {
  collectConversationAttachments,
  createPollPayload,
  summarizePollVotes,
} from './conversationFeatures';

function handle(id: string, mimeType: string): AttachmentHandle {
  return {
    id,
    storagePath: 'conversation/' + id + '.bin',
    mimeType,
    sizeBytes: 2048,
    keyB64: 'key',
    nonceB64: 'nonce',
  };
}

function message(id: string, createdAt: string, attachments: AttachmentHandle[]): DecryptedMessage {
  return {
    id,
    conversationId: 'conv-1',
    senderId: 'sender-1',
    senderDeviceId: 'device-1',
    replyToId: null,
    editedAt: null,
    deletedAt: null,
    createdAt,
    plaintext: JSON.stringify({ v: 1, type: 'text', text: '', attachments }),
  };
}

describe('collectConversationAttachments', () => {
  it('indexes media, audio, and files newest first', () => {
    const first = message('m1', '2026-04-24T09:00:00.000Z', [
      handle('img-1', 'image/png'),
      handle('file-1', 'application/pdf'),
    ]);
    const second = message('m2', '2026-04-24T10:00:00.000Z', [
      handle('audio-1', 'audio/webm'),
      handle('video-1', 'video/mp4'),
    ]);

    const index = collectConversationAttachments([first, second]);

    expect(index.media.map((item) => item.handle.id)).toEqual(['video-1', 'img-1']);
    expect(index.audio.map((item) => item.handle.id)).toEqual(['audio-1']);
    expect(index.files.map((item) => item.handle.id)).toEqual(['file-1']);
    expect(index.all.map((item) => item.messageId)).toEqual(['m2', 'm2', 'm1', 'm1']);
  });
});

describe('createPollPayload', () => {
  it('creates a parseable encrypted-message poll payload', () => {
    const payload = createPollPayload('  Lieblings Feature?  ', [' Media Drawer ', '', 'Polls']);
    const parsed = parseMessagePayload(payload);

    expect(parsed.kind).toBe('poll');
    if (parsed.kind !== 'poll') throw new Error('expected poll payload');
    expect(parsed.question).toBe('Lieblings Feature?');
    expect(parsed.options).toEqual([
      { id: 'option-1', emoji: '1️⃣', text: 'Media Drawer' },
      { id: 'option-2', emoji: '2️⃣', text: 'Polls' },
    ]);
  });

  it('requires a question and at least two non-empty options', () => {
    expect(() => createPollPayload('', ['A', 'B'])).toThrow('question');
    expect(() => createPollPayload('Feature?', ['A', ''])).toThrow('options');
  });
});

describe('summarizePollVotes', () => {
  it('counts only configured poll options and marks the current user vote', () => {
    const summary = summarizePollVotes(
      [
        { id: 'option-1', emoji: '1️⃣', text: 'Media Drawer' },
        { id: 'option-2', emoji: '2️⃣', text: 'Polls' },
      ],
      [
        { emoji: '1️⃣', count: 3, mine: false },
        { emoji: '2️⃣', count: 1, mine: true },
        { emoji: '🔥', count: 99, mine: true },
      ],
    );

    expect(summary.totalVotes).toBe(4);
    expect(summary.options.map((option) => option.percent)).toEqual([75, 25]);
    expect(summary.options.map((option) => option.mine)).toEqual([false, true]);
  });
});
