import {
  parseMessagePayload,
  serializeMessagePayload,
  type AttachmentHandle,
  type DecryptedMessage,
  type PollOption,
} from '@chat-app/shared/chat';

export type AttachmentBucket = 'media' | 'audio' | 'files';

export interface ConversationAttachmentItem {
  messageId: string;
  senderId: string;
  createdAt: string;
  handle: AttachmentHandle;
  bucket: AttachmentBucket;
}

export interface ConversationAttachmentIndex {
  all: ConversationAttachmentItem[];
  media: ConversationAttachmentItem[];
  audio: ConversationAttachmentItem[];
  files: ConversationAttachmentItem[];
}

interface ReactionSummaryInput {
  emoji: string;
  count: number;
  mine: boolean;
}

export interface PollVoteOptionSummary extends PollOption {
  count: number;
  mine: boolean;
  percent: number;
}

export interface PollVoteSummary {
  totalVotes: number;
  options: PollVoteOptionSummary[];
}

export const POLL_OPTION_EMOJIS = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟'];

export function collectConversationAttachments(
  messages: DecryptedMessage[],
): ConversationAttachmentIndex {
  const all: ConversationAttachmentItem[] = [];

  for (const message of messages) {
    if (message.deletedAt || !message.plaintext) continue;
    const parsed = parseMessagePayload(message.plaintext);
    if (parsed.kind !== 'text') continue;

    for (const handle of parsed.attachments) {
      all.push({
        messageId: message.id,
        senderId: message.senderId,
        createdAt: message.createdAt,
        handle,
        bucket: bucketForMime(handle.mimeType),
      });
    }
  }

  all.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));

  return {
    all,
    media: all.filter((item) => item.bucket === 'media'),
    audio: all.filter((item) => item.bucket === 'audio'),
    files: all.filter((item) => item.bucket === 'files'),
  };
}

export function createPollPayload(question: string, optionTexts: string[]): string {
  const trimmedQuestion = question.trim();
  if (!trimmedQuestion) throw new Error('poll question is required');

  const options: PollOption[] = optionTexts
    .map((text) => text.trim())
    .filter(Boolean)
    .slice(0, POLL_OPTION_EMOJIS.length)
    .map((text, idx) => ({
      id: 'option-' + (idx + 1),
      emoji: POLL_OPTION_EMOJIS[idx]!,
      text,
    }));

  if (options.length < 2) throw new Error('poll requires at least two options');

  return serializeMessagePayload({
    v: 1,
    type: 'poll',
    question: trimmedQuestion,
    options,
  });
}

export function summarizePollVotes(
  options: PollOption[],
  reactions: ReactionSummaryInput[],
): PollVoteSummary {
  const reactionByEmoji = new Map(reactions.map((reaction) => [reaction.emoji, reaction]));
  const totalVotes = options.reduce(
    (sum, option) => sum + (reactionByEmoji.get(option.emoji)?.count ?? 0),
    0,
  );

  return {
    totalVotes,
    options: options.map((option) => {
      const reaction = reactionByEmoji.get(option.emoji);
      const count = reaction?.count ?? 0;
      return {
        ...option,
        count,
        mine: reaction?.mine ?? false,
        percent: totalVotes > 0 ? Math.round((count / totalVotes) * 100) : 0,
      };
    }),
  };
}

function bucketForMime(mimeType: string): AttachmentBucket {
  if (mimeType.startsWith('image/') || mimeType.startsWith('video/')) return 'media';
  if (mimeType.startsWith('audio/')) return 'audio';
  return 'files';
}
