import type {
  Message,
  TextChannel,
  ThreadChannel,
} from "discord.js-selfbot-v13";

export interface MessageLocation {
  channelId: string;
  threadId: string | null;
  threadName: string | null;
  channelName: string | null;
}

export interface StickerEvidence {
  id: string;
  name: string;
  url: string;
  format: string | null;
}

export interface EmbedEvidence {
  title: string | null;
  description: string | null;
  url: string | null;
  color: number | null;
  image: string | null;
  thumbnail: string | null;
  author: {
    name: string | null;
    url: string | null;
    iconURL: string | null;
  } | null;
  footer: { text: string | null; iconURL: string | null } | null;
  fields: Array<{ name: string; value: string; inline: boolean }>;
}

export interface AttachmentEvidence {
  id: string;
  name: string;
  url: string;
  contentType: string | null;
  size: number;
}

export interface MessageMediaEvidence {
  stickers: StickerEvidence[];
  embeds: EmbedEvidence[];
  attachments: AttachmentEvidence[];
}

export interface RichMessageMetadata {
  stickers: Array<StickerEvidence>;
  embeds: Array<EmbedEvidence>;
  attachments: Array<AttachmentEvidence>;
  author: {
    id: string;
    username: string;
    tag: string | null;
    avatarURL: string | null;
    bot: boolean;
  };
  member: {
    displayName: string | null;
    roles: Array<{ id: string; name: string }>;
    joinedTimestamp: number | null;
  } | null;
  channel: MessageLocation;
  reference: {
    messageId: string | null;
    channelId: string | null;
    guildId: string | null;
  } | null;
}

export function getMessageLocation(message: Message): MessageLocation {
  const channel = message.channel as TextChannel | ThreadChannel;
  if (!channel.isThread?.()) {
    return {
      channelId: message.channelId,
      threadId: null,
      threadName: null,
      channelName: "name" in channel ? channel.name : null,
    };
  }

  return {
    channelId: channel.parentId ?? message.channelId,
    threadId: channel.id,
    threadName: channel.name,
    channelName: channel.parent?.name ?? null,
  };
}

export function getStickerMetadata(
  message: Message,
): RichMessageMetadata["stickers"] {
  return Array.from(message.stickers.values()).map((sticker) => ({
    id: sticker.id,
    name: sticker.name,
    url: sticker.url,
    format: sticker.format ?? null,
  }));
}

export function getAttachmentMetadata(
  message: Message,
): RichMessageMetadata["attachments"] {
  return Array.from(message.attachments.values()).map((attachment) => ({
    id: attachment.id,
    name: attachment.name || "unknown",
    url: attachment.url,
    contentType: attachment.contentType ?? null,
    size: attachment.size,
  }));
}

export function getEmbedMetadata(
  message: Message,
): RichMessageMetadata["embeds"] {
  return message.embeds.map((embed) => ({
    title: embed.title ?? null,
    description: embed.description ?? null,
    url: embed.url ?? null,
    color: embed.color ?? null,
    image: embed.image?.url ?? null,
    thumbnail: embed.thumbnail?.url ?? null,
    author: embed.author
      ? {
          name: embed.author.name ?? null,
          url: embed.author.url ?? null,
          iconURL: embed.author.iconURL ?? null,
        }
      : null,
    footer: embed.footer
      ? {
          text: embed.footer.text ?? null,
          iconURL: embed.footer.iconURL ?? null,
        }
      : null,
    fields: embed.fields.map((field) => ({
      name: field.name,
      value: field.value,
      inline: Boolean(field.inline),
    })),
  }));
}

export function getMessageMetadata(message: Message): RichMessageMetadata {
  const member = message.member;
  return {
    stickers: getStickerMetadata(message),
    embeds: getEmbedMetadata(message),
    attachments: getAttachmentMetadata(message),
    author: {
      id: message.author.id,
      username: message.author.username,
      tag: "tag" in message.author ? message.author.tag : null,
      avatarURL: message.author.avatarURL() ?? null,
      bot: Boolean(message.author.bot),
    },
    member: member
      ? {
          displayName: member.displayName ?? null,
          roles: member.roles.cache.map((role) => ({
            id: role.id,
            name: role.name,
          })),
          joinedTimestamp: member.joinedTimestamp ?? null,
        }
      : null,
    channel: getMessageLocation(message),
    reference: message.reference
      ? {
          messageId: message.reference.messageId ?? null,
          channelId: message.reference.channelId ?? null,
          guildId: message.reference.guildId ?? null,
        }
      : null,
  };
}

export function parseRichMessageMetadata(
  metadata: string | null | undefined,
): RichMessageMetadata | null {
  if (!metadata) return null;

  try {
    const parsed = JSON.parse(metadata) as Partial<RichMessageMetadata>;
    return {
      stickers: Array.isArray(parsed.stickers) ? parsed.stickers : [],
      embeds: Array.isArray(parsed.embeds) ? parsed.embeds : [],
      attachments: Array.isArray(parsed.attachments) ? parsed.attachments : [],
      author: parsed.author as RichMessageMetadata["author"],
      member: (parsed.member ?? null) as RichMessageMetadata["member"],
      channel: parsed.channel as RichMessageMetadata["channel"],
      reference: (parsed.reference ?? null) as RichMessageMetadata["reference"],
    };
  } catch {
    return null;
  }
}

export function extractMessageMediaEvidence(
  metadata: string | null | undefined,
): MessageMediaEvidence {
  const parsed = parseRichMessageMetadata(metadata);
  return {
    stickers: parsed?.stickers ?? [],
    embeds: parsed?.embeds ?? [],
    attachments: parsed?.attachments ?? [],
  };
}

export function formatMediaEvidenceForPrompt(
  metadata: string | null | undefined,
): string {
  const evidence = extractMessageMediaEvidence(metadata);
  const parts: string[] = [];

  if (evidence.stickers.length > 0) {
    parts.push(
      `[stickers: ${evidence.stickers
        .map((sticker) =>
          [`name=${sticker.name}`, sticker.url ? `url=${sticker.url}` : null]
            .filter(Boolean)
            .join(", "),
        )
        .join(" | ")}]`,
    );
  }

  if (evidence.embeds.length > 0) {
    parts.push(
      `[embeds: ${evidence.embeds
        .map((embed) =>
          [
            embed.title ? `title=${embed.title}` : null,
            embed.description ? `description=${embed.description}` : null,
            embed.url ? `url=${embed.url}` : null,
            embed.image ? `image=${embed.image}` : null,
            embed.thumbnail ? `thumbnail=${embed.thumbnail}` : null,
            embed.fields.length > 0
              ? `fields=${embed.fields.map((field) => `${field.name}: ${field.value}`).join("; ")}`
              : null,
          ]
            .filter(Boolean)
            .join(", "),
        )
        .join(" | ")}]`,
    );
  }

  if (evidence.attachments.length > 0) {
    parts.push(
      `[attachments: ${evidence.attachments
        .map((attachment) =>
          [
            `name=${attachment.name}`,
            attachment.contentType ? `type=${attachment.contentType}` : null,
            `size=${attachment.size}`,
            attachment.url ? `url=${attachment.url}` : null,
          ]
            .filter(Boolean)
            .join(", "),
        )
        .join(" | ")}]`,
    );
  }

  return parts.join(" ");
}

export function getDisplayContent(message: Message): string {
  if (message.content.trim().length > 0) return message.content;

  const stickers = getStickerMetadata(message);
  if (stickers.length > 0) {
    return stickers.map((sticker) => `[Sticker: ${sticker.name}]`).join(" ");
  }

  const attachments = getAttachmentMetadata(message);
  if (attachments.length > 0) {
    return attachments
      .map((attachment) => `[Attachment: ${attachment.name}]`)
      .join(" ");
  }

  const embeds = getEmbedMetadata(message);
  if (embeds.length > 0) {
    return embeds
      .map((embed) => embed.title || embed.description || "[Embed]")
      .join(" ");
  }

  return "";
}
