/**
 * 图片压缩工具类
 * 将图片压缩到指定尺寸和文件大小
 */

export interface CompressOptions {
    width?: number;
    height?: number;
    quality?: number;
    maxSize?: number; // KB
}

export const compressImage = (
    file: File,
    options: CompressOptions = {}
): Promise<File> => {
    const {
        quality = 0.8
    } = options;

    return new Promise((resolve, reject) => {
        if (!file || !file.type.includes('image')) {
            reject(new Error('无效的图片文件'));
            return;
        }

        const fileSizeKB = file.size / 1024;
        const targetSizeKB = fileSizeKB / 2;


        // 对于小文件，直接尝试转换格式压缩
        if (fileSizeKB < 300 && file.type === 'image/png') {

            const reader = new FileReader();
            reader.onload = (e) => {
                const img = new Image();
                img.onload = () => {
                    compressSmallPngToJpeg(img, file, targetSizeKB, resolve, reject);
                };
                img.onerror = () => reject(new Error('图片加载失败'));
                img.src = e.target?.result as string;
            };
            reader.onerror = () => reject(new Error('文件读取失败'));
            reader.readAsDataURL(file);
            return;
        }

        // 正常压缩流程
        const reader = new FileReader();
        reader.onload = (e) => {
            const img = new Image();
            img.onload = () => {
                compressToHalfSize(img, file, quality, resolve, reject);
            };
            img.onerror = () => reject(new Error('图片加载失败'));
            img.src = e.target?.result as string;
        };
        reader.onerror = () => reject(new Error('文件读取失败'));
        reader.readAsDataURL(file);
    });
};

// PNG小文件转JPEG压缩
function compressSmallPngToJpeg(
    img: HTMLImageElement,
    originalFile: File,
    targetSizeKB: number,
    resolve: (file: File) => void,
    reject: (error: Error) => void
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
        reject(new Error('浏览器不支持Canvas'));
        return;
    }


    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0, img.width, img.height);

    // 尝试转换为JPEG格式并压缩
    const compressAsJpeg = (quality: number): void => {
        canvas.toBlob(
            (blob) => {
                if (!blob) {
                    reject(new Error('JPEG转换失败'));
                    return;
                }

                const sizeKB = blob.size / 1024;

                if (sizeKB <= targetSizeKB || quality <= 0.1) {
                    // 创建新的JPEG文件
                    const jpegFileName = originalFile.name.replace(/\.png$/i, '.jpg');
                    const compressedFile = new File([blob], jpegFileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });

                    const originalSizeKB = originalFile.size / 1024;
                    resolve(compressedFile);
                } else {
                    const nextQuality = Math.max(0.1, quality - 0.1);
                    compressAsJpeg(nextQuality);
                }
            },
            'image/jpeg', // 强制转换为JPEG
            quality
        );
    };

    compressAsJpeg(0.7); // 从0.7质量开始
}

// 图片处理函数 - 压缩到原文件一半大小
function compressToHalfSize(
    img: HTMLImageElement,
    originalFile: File,
    initialQuality: number,
    resolve: (file: File) => void,
    reject: (error: Error) => void
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
        reject(new Error('浏览器不支持Canvas'));
        return;
    }

    const originalSizeKB = originalFile.size / 1024;
    const targetSizeKB = originalSizeKB / 2;


    // 对于小文件(< 200KB)，直接用低质量压缩，不测试
    if (originalSizeKB < 200) {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0, img.width, img.height);

        // 直接从低质量开始压缩
        const compressDirectly = (quality: number): void => {
            canvas.toBlob((blob) => {
                if (!blob) {
                    reject(new Error('图片处理失败'));
                    return;
                }

                const sizeKB = blob.size / 1024;

                if (sizeKB <= targetSizeKB || quality <= 0.1) {
                    const compressedFile = new File([blob], originalFile.name, {
                        type: originalFile.type,
                        lastModified: Date.now()
                    });

                    const compressionRatio = (sizeKB / originalSizeKB * 100).toFixed(1);
                    resolve(compressedFile);
                } else {
                    const nextQuality = Math.max(0.1, quality - 0.1);
                    compressDirectly(nextQuality);
                }
            }, originalFile.type, quality);
        };

        compressDirectly(0.5); // 从0.5开始
        return;
    }

    // 大文件才做测试
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0, img.width, img.height);

    // 先用初始质量测试一下
    canvas.toBlob((testBlob) => {
        if (!testBlob) {
            reject(new Error('图片处理失败'));
            return;
        }

        const testSizeKB = testBlob.size / 1024;

        // 如果初始处理后比原文件大很多(超过10%)，直接返回原文件
        if (testSizeKB > originalSizeKB * 1.1) {
            resolve(originalFile);
            return;
        }

        // 如果Canvas处理后已经达到或接近目标大小，直接返回
        if (testSizeKB <= targetSizeKB) {
            const compressedFile = new File([testBlob], originalFile.name, {
                type: originalFile.type,
                lastModified: Date.now()
            });
            resolve(compressedFile);
            return;
        }

        // 开始压缩循环 - 只降低质量，不提高
        const compress = (currentQuality: number): void => {
            canvas.toBlob(
                (blob) => {
                    if (!blob) {
                        reject(new Error('图片处理失败'));
                        return;
                    }

                    const sizeKB = blob.size / 1024;

                    // 如果达到目标大小，立即返回
                    if (sizeKB <= targetSizeKB) {
                        const compressedFile = new File([blob], originalFile.name, {
                            type: originalFile.type,
                            lastModified: Date.now()
                        });

                        const compressionRatio = (sizeKB / originalSizeKB * 100).toFixed(1);

                        resolve(compressedFile);
                    } else if (currentQuality <= 0.1) {
                        // 质量已经很低但还没达到目标，返回当前结果
                        const compressedFile = new File([blob], originalFile.name, {
                            type: originalFile.type,
                            lastModified: Date.now()
                        });

                        const compressionRatio = (sizeKB / originalSizeKB * 100).toFixed(1);

                        resolve(compressedFile);
                    } else {
                        // 文件还是太大，继续降低质量
                        const nextQuality = Math.max(0.05, currentQuality - 0.1);
                        compress(nextQuality);
                    }
                },
                originalFile.type,
                currentQuality
            );
        };

        // 从初始质量开始压缩
        compress(initialQuality);

    }, originalFile.type, initialQuality);
}