// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { MessageAttributesType } from '../model-types.d.ts';
import type { AttachmentType } from '../types/Attachment.std.ts';

export function getFilePathsReferencedByAttachment(
  attachment: AttachmentType
): {
  externalAttachments: Set<string>;
  externalDownloads: Set<string>;
} {
  const externalAttachments = new Set<string>();
  const externalDownloads = new Set<string>();

  // Copied attachments weakly reference their paths -- there is a chance that
  // non-normalized attachments may still exist on messages.json, in which case
  // `isAttachmentSafeToDelete` would incorrectly mark a copied thumbnail as safe to
  // delete
  if (attachment.copied) {
    return { externalAttachments, externalDownloads };
  }

  const { path, thumbnail, screenshot, thumbnailFromBackup, downloadPath } =
    attachment;
  if (path) {
    externalAttachments.add(path);
  }

  // downloadPath is relative to downloads folder and has to be tracked
  // separately.
  if (downloadPath) {
    externalDownloads.add(downloadPath);
  }

  if (thumbnail && thumbnail.path) {
    externalAttachments.add(thumbnail.path);
  }

  if (screenshot && screenshot.path) {
    externalAttachments.add(screenshot.path);
  }

  if (thumbnailFromBackup && thumbnailFromBackup.path) {
    externalAttachments.add(thumbnailFromBackup.path);
  }
  return { externalAttachments, externalDownloads };
}

function getFilePathsForVersionOfMessage(
  rootOrEditHistoryMessage: Partial<MessageAttributesType>
): {
  externalAttachments: Set<string>;
  externalDownloads: Set<string>;
} {
  const externalAttachments = new Set<string>();
  const externalDownloads = new Set<string>();
  function addFilePathsReferencedByAttachment(attachment: AttachmentType) {
    const result = getFilePathsReferencedByAttachment(attachment);
    result.externalAttachments.forEach(path => externalAttachments.add(path));
    result.externalDownloads.forEach(path => externalDownloads.add(path));
  }

  const { attachments, bodyAttachment, contact, quote, preview, sticker } =
    rootOrEditHistoryMessage;

  attachments?.forEach(addFilePathsReferencedByAttachment);

  if (bodyAttachment) {
    addFilePathsReferencedByAttachment(bodyAttachment);
  }

  if (quote?.attachments) {
    quote.attachments.forEach(attachment => {
      if (attachment.thumbnail) {
        addFilePathsReferencedByAttachment(attachment.thumbnail);
      }
    });
  }

  if (contact) {
    contact.forEach(item => {
      if (item.avatar?.avatar) {
        addFilePathsReferencedByAttachment(item.avatar.avatar);
      }
    });
  }

  if (preview) {
    preview.forEach(item => {
      if (item.image) {
        addFilePathsReferencedByAttachment(item.image);
      }
    });
  }

  if (sticker?.data) {
    addFilePathsReferencedByAttachment(sticker.data);
  }
  return { externalAttachments, externalDownloads };
}

export function getFilePathsReferencedByMessage(
  message: MessageAttributesType
): {
  externalAttachments: Array<string>;
  externalDownloads: Array<string>;
} {
  const externalAttachments = new Set<string>();
  const externalDownloads = new Set<string>();

  [message, ...(message.editHistory ?? [])].forEach(version => {
    const result = getFilePathsForVersionOfMessage(version);
    result.externalAttachments.forEach(path => externalAttachments.add(path));
    result.externalDownloads.forEach(path => externalDownloads.add(path));
  });

  return {
    externalAttachments: [...externalAttachments],
    externalDownloads: [...externalDownloads],
  };
}
