export const IMAGE_COMPRESS_THRESHOLD = 0.8 * 1024 * 1024;

export interface CompressImageOptions {
  maxBytes?: number;
  maxWidth?: number;
  minQuality?: number;
  initialQuality?: number;
  onProgress?: (message: string) => void;
}

export interface CompressImageResult {
  file: File;
  skipped: boolean;
}

export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  const value = bytes / k ** i;
  return `${Number.parseFloat(value.toFixed(2))} ${sizes[i]}`;
}

/** 压缩节省比例文案，如「约节省 42%」 */
export function formatSavingsPercent(
  originalBytes: number,
  compressedBytes: number,
): string {
  if (originalBytes <= 0 || compressedBytes >= originalBytes) {
    return '';
  }
  const percent = Math.round(
    ((originalBytes - compressedBytes) / originalBytes) * 100,
  );
  return percent > 0 ? `（约节省 ${percent}%）` : '';
}

function loadImageFromFile(file: File): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => {
      URL.revokeObjectURL(url);
      resolve(img);
    };
    img.onerror = () => {
      URL.revokeObjectURL(url);
      reject(new Error('图片加载失败'));
    };
    img.src = url;
  });
}

function canvasToBlob(
  canvas: HTMLCanvasElement,
  type: string,
  quality: number,
): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('图片压缩失败'));
        }
      },
      type,
      quality,
    );
  });
}

function getOutputType(file: File): string {
  if (file.type === 'image/png' || file.type === 'image/webp') {
    return file.type;
  }
  return 'image/jpeg';
}

function buildCompressedFile(
  blob: Blob,
  originalFile: File,
  outputType: string,
): File {
  const ext = outputType === 'image/png' ? '.png' : '.jpg';
  const baseName = originalFile.name.replace(/\.[^.]+$/, '') || 'image';
  return new File([blob], `${baseName}${ext}`, {
    type: outputType,
    lastModified: Date.now(),
  });
}

export async function compressImageFile(
  file: File,
  options: CompressImageOptions = {},
): Promise<CompressImageResult> {
  const {
    maxBytes = IMAGE_COMPRESS_THRESHOLD,
    maxWidth = 1920,
    minQuality = 0.5,
    initialQuality = 0.85,
    onProgress,
  } = options;

  if (file.type === 'image/gif') {
    return { file, skipped: true };
  }

  onProgress?.('正在加载图片…');

  const img = await loadImageFromFile(file);
  let width = img.naturalWidth;
  let height = img.naturalHeight;

  if (width > maxWidth || height > maxWidth) {
    if (width >= height) {
      height = Math.round((height * maxWidth) / width);
      width = maxWidth;
    } else {
      width = Math.round((width * maxWidth) / height);
      height = maxWidth;
    }
  }

  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  if (!ctx) {
    throw new Error('无法创建 Canvas 上下文');
  }
  ctx.drawImage(img, 0, 0, width, height);

  const outputType = getOutputType(file);
  let quality = initialQuality;
  onProgress?.(`正在压缩（质量 ${Math.round(quality * 100)}%）…`);
  let blob = await canvasToBlob(canvas, outputType, quality);

  while (blob.size > maxBytes && quality > minQuality) {
    quality = Math.max(minQuality, quality - 0.1);
    onProgress?.(`正在压缩（质量 ${Math.round(quality * 100)}%）…`);
    blob = await canvasToBlob(canvas, outputType, quality);
  }

  const compressedFile = buildCompressedFile(blob, file, outputType);
  return { file: compressedFile, skipped: false };
}
