const DEFAULT_MAX_EDGE = 2560;
const DEFAULT_QUALITY = 0.82;

function loadImageFromFile(file: File) {
  return new Promise<HTMLImageElement>((resolve, reject) => {
    const url = URL.createObjectURL(file);
    const image = new Image();
    image.onload = () => {
      URL.revokeObjectURL(url);
      resolve(image);
    };
    image.onerror = () => {
      URL.revokeObjectURL(url);
      reject(new Error('Не удалось прочитать изображение'));
    };
    image.src = url;
  });
}

function canvasToBlob(canvas: HTMLCanvasElement, type: string, quality: number) {
  return new Promise<Blob>((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (!blob) {
          reject(new Error('Не удалось сжать изображение'));
          return;
        }
        resolve(blob);
      },
      type,
      quality
    );
  });
}

export function isCompressibleImageFile(file: File) {
  const type = (file.type || '').toLowerCase();
  if (type.startsWith('image/') && !type.includes('gif') && !type.includes('svg')) {
    return true;
  }
  return /\.(jpe?g|png|webp|heic|heif|bmp)$/i.test(file.name);
}

export async function compressChatImage(
  file: File,
  options?: { maxEdge?: number; quality?: number }
) {
  const maxEdge = options?.maxEdge ?? DEFAULT_MAX_EDGE;
  const quality = options?.quality ?? DEFAULT_QUALITY;

  if (!isCompressibleImageFile(file)) {
    return { file, width: undefined, height: undefined, compressed: false };
  }

  const image = await loadImageFromFile(file);
  const width = image.naturalWidth || image.width;
  const height = image.naturalHeight || image.height;
  if (!width || !height) {
    return { file, width: undefined, height: undefined, compressed: false };
  }

  const scale = Math.min(1, maxEdge / Math.max(width, height));
  const targetWidth = Math.max(1, Math.round(width * scale));
  const targetHeight = Math.max(1, Math.round(height * scale));

  if (scale >= 1 && file.size <= 350_000) {
    return { file, width, height, compressed: false };
  }

  const canvas = document.createElement('canvas');
  canvas.width = targetWidth;
  canvas.height = targetHeight;
  const context = canvas.getContext('2d');
  if (!context) {
    return { file, width, height, compressed: false };
  }

  context.drawImage(image, 0, 0, targetWidth, targetHeight);

  const outputType = file.type === 'image/png' ? 'image/jpeg' : file.type || 'image/jpeg';
  const blob = await canvasToBlob(canvas, outputType, quality);
  const extension = outputType.includes('webp') ? 'webp' : 'jpg';
  const baseName = file.name.replace(/\.[^.]+$/, '') || 'image';
  const compressedFile = new File([blob], `${baseName}.${extension}`, { type: outputType, lastModified: Date.now() });

  return {
    file: compressedFile,
    width: targetWidth,
    height: targetHeight,
    compressed: true
  };
}

export async function readImageDimensions(file: File) {
  if (!isCompressibleImageFile(file)) {
    return { width: undefined, height: undefined };
  }
  try {
    const image = await loadImageFromFile(file);
    return {
      width: image.naturalWidth || image.width,
      height: image.naturalHeight || image.height
    };
  } catch {
    return { width: undefined, height: undefined };
  }
}

export function createFilePreviewUrl(file: File) {
  if (file.type.startsWith('image/')) {
    return URL.createObjectURL(file);
  }
  return null;
}
