import { needsBlobObjectUrlForInlineDisplay } from './attachment-display-url.rules';

const IMAGE_EXTENSIONS = new Set([
  '.apng',
  '.avif',
  '.bmp',
  '.gif',
  '.heic',
  '.heif',
  '.jpg',
  '.jpeg',
  '.png',
  '.svg',
  '.webp'
]);

export interface ImageAttachmentCandidate {
  available: boolean;
  filename: string;
  filePath?: string;
  id: string;
  isImage: boolean;
  mime: string;
  objectUrl?: string;
  savedPath?: string;
}

export function hasImageFilename(filename: string): boolean {
  const normalized = filename.trim().toLowerCase();
  const extensionIndex = normalized.lastIndexOf('.');

  if (extensionIndex <= 0) {
    return false;
  }

  return IMAGE_EXTENSIONS.has(normalized.slice(extensionIndex));
}

export function isImageAttachment(attachment: Pick<ImageAttachmentCandidate, 'filename' | 'isImage' | 'mime'>): boolean {
  return attachment.isImage ||
    attachment.mime.startsWith('image/') ||
    hasImageFilename(attachment.filename);
}

export function isInlineDisplayableImage(
  attachment: Pick<ImageAttachmentCandidate, 'available' | 'objectUrl'>
): boolean {
  return attachment.available &&
    !!attachment.objectUrl &&
    !needsBlobObjectUrlForInlineDisplay(attachment.objectUrl);
}

export function imageAttachmentDisplayRank(
  attachment: Pick<ImageAttachmentCandidate, 'available' | 'filePath' | 'isImage' | 'objectUrl' | 'savedPath'>
): number {
  if (isInlineDisplayableImage(attachment)) {
    return 4;
  }

  if (attachment.savedPath || attachment.filePath) {
    return 3;
  }

  if (attachment.available && attachment.objectUrl) {
    return 2;
  }

  if (attachment.isImage) {
    return 1;
  }

  return 0;
}

export function dedupeImageAttachmentsForDisplay<T extends ImageAttachmentCandidate>(attachments: readonly T[]): T[] {
  const byFilename = new Map<string, T>();

  for (const attachment of attachments) {
    if (!isImageAttachment(attachment)) {
      continue;
    }

    const key = attachment.filename.trim().toLowerCase();
    const existing = byFilename.get(key);

    if (!existing || imageAttachmentDisplayRank(attachment) > imageAttachmentDisplayRank(existing)) {
      byFilename.set(key, attachment);
    }
  }

  return Array.from(byFilename.values());
}

export function resolvePublishAttachmentIsImage(file: Pick<File, 'name' | 'type'>): boolean {
  return file.type.startsWith('image/') || hasImageFilename(file.name);
}
