import { __ } from './i18n';
import { attachmentBlob } from './api';

export interface ImageExportOptions {
  attachmentId: number;
  ownerReviewId?: number;
  originalName: string;
  originalMimeType: string;
  convertToWebp: boolean;
  compressionPercent: number;
  maxSize: number;
  filename: string;
}

const MAX_EXPORT_DIMENSION = 10_000;

function cleanFilename(value: string, fallback: string): string {
  const filename = value
    .trim()
    .replace(/[\\/]+/g, '-')
    .replace(/[\u0000-\u001F<>:"|?*]+/g, '')
    .replace(/^\.+$/, '');
  return filename || fallback;
}

function baseFilename(value: string): string {
  const withoutExtension = value.replace(/\.[^.]+$/, '').trim();
  return withoutExtension || 'image';
}

function extensionForMimeType(mimeType: string): string {
  switch (mimeType.toLowerCase()) {
    case 'image/jpeg': return 'jpg';
    case 'image/webp': return 'webp';
    case 'image/png': return 'png';
    case 'image/gif': return 'gif';
    case 'image/avif': return 'avif';
    default: return 'png';
  }
}

function canvasMimeType(mimeType: string): string {
  return ['image/jpeg', 'image/png', 'image/webp'].includes(mimeType.toLowerCase())
    ? mimeType.toLowerCase()
    : 'image/png';
}

function outputFilename(input: string, originalName: string, mimeType: string): string {
  const fallback = cleanFilename(originalName, 'image');
  const filename = cleanFilename(input, fallback);
  return `${baseFilename(filename)}.${extensionForMimeType(mimeType)}`;
}

function downloadBlob(blob: Blob, filename: string): void {
  const objectUrl = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = objectUrl;
  link.download = filename;
  link.style.display = 'none';
  document.body.append(link);
  link.click();
  link.remove();
  window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1_000);
}

function decodeImage(blob: Blob): Promise<{ image: HTMLImageElement; dispose: () => void }> {
  return new Promise((resolve, reject) => {
    const objectUrl = URL.createObjectURL(blob);
    const image = new Image();
    const dispose = () => URL.revokeObjectURL(objectUrl);
    image.onload = () => resolve({ image, dispose });
    image.onerror = () => {
      dispose();
      reject(new Error(__('This image could not be prepared for download.', 'commentmate')));
    };
    image.src = objectUrl;
  });
}

function canvasBlob(canvas: HTMLCanvasElement, mimeType: string, quality: number): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob((blob) => {
      if (blob) resolve(blob);
      else reject(new Error(__('Your browser could not create the exported image.', 'commentmate')));
    }, mimeType, quality);
  });
}

function normalizedDimension(value: number): number {
  if (!Number.isFinite(value)) return 1500;
  return Math.max(1, Math.min(MAX_EXPORT_DIMENSION, Math.round(value)));
}

function normalizedQuality(value: number): number {
  if (!Number.isFinite(value)) return 0.8;
  return Math.max(0.1, Math.min(1, value / 100));
}

/** Download the uploaded source bytes without conversion or resizing. */
export async function downloadOriginalImage({ attachmentId, ownerReviewId, originalName }: Pick<ImageExportOptions, 'attachmentId' | 'ownerReviewId' | 'originalName'>): Promise<void> {
  const blob = await attachmentBlob(attachmentId, ownerReviewId);
  downloadBlob(blob, outputFilename(originalName, originalName, blob.type));
}

/** Resize and optionally convert an uploaded image in the browser before downloading it. */
export async function exportImage(options: ImageExportOptions): Promise<void> {
  const source = await attachmentBlob(options.attachmentId, options.ownerReviewId);
  const { image, dispose } = await decodeImage(source);

  try {
    const maxDimension = normalizedDimension(options.maxSize);
    const sourceWidth = image.naturalWidth;
    const sourceHeight = image.naturalHeight;
    if (!sourceWidth || !sourceHeight) throw new Error(__('This image does not have usable dimensions.', 'commentmate'));

    const scale = Math.min(1, maxDimension / sourceWidth);
    const width = Math.max(1, Math.round(sourceWidth * scale));
    const height = Math.max(1, Math.round(sourceHeight * scale));
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const context = canvas.getContext('2d');
    if (!context) throw new Error(__('Your browser could not prepare the image for download.', 'commentmate'));
    context.drawImage(image, 0, 0, width, height);

    const requestedMimeType = options.convertToWebp
      ? 'image/webp'
      : canvasMimeType(source.type || options.originalMimeType);
    const exported = await canvasBlob(canvas, requestedMimeType, normalizedQuality(options.compressionPercent));
    if (options.convertToWebp && exported.type !== 'image/webp') {
      throw new Error(__('Your browser does not support WebP export. Turn off conversion and try again.', 'commentmate'));
    }

    downloadBlob(exported, outputFilename(options.filename, options.originalName, exported.type || requestedMimeType));
  } finally {
    dispose();
  }
}
