/**
 * Kompresi gambar client-side menggunakan Canvas API.
 *
 * Fitur:
 * - Auto-orientasi berdasarkan EXIF (via createImageBitmap)
 * - Resize proporsional bila melebihi maxDimension
 * - Output WebP (fallback ke JPEG bila browser tidak support)
 * - Tidak memodifikasi file asli — mengembalikan File baru
 */

export type CompressionOptions = {
    /** Kualitas output 0–1 (default: 0.8). */
    quality?: number;
    /** Dimensi maksimum (width/height) dalam px (default: 1920). */
    maxDimension?: number;
    /** Output MIME type (default: 'image/webp'). */
    mimeType?: 'image/webp' | 'image/jpeg' | 'image/png';
};

export type CompressionResult = {
    /** File hasil kompresi. */
    file: File;
    /** Ukuran asli dalam bytes. */
    originalSize: number;
    /** Ukuran setelah kompresi dalam bytes. */
    compressedSize: number;
    /** Persentase pengurangan (0–100). */
    savings: number;
    /** Lebar final dalam px. */
    width: number;
    /** Tinggi final dalam px. */
    height: number;
};

const DEFAULTS: Required<CompressionOptions> = {
    quality: 0.8,
    maxDimension: 1920,
    mimeType: 'image/webp',
};

/**
 * Cek apakah file adalah gambar yang bisa dikompresi.
 */
export function isCompressibleImage(file: File): boolean {
    return file.type.startsWith('image/') && file.type !== 'image/svg+xml';
}

/**
 * Kompresi gambar tunggal.
 *
 * @returns CompressionResult — file baru + metadata ukuran.
 */
export async function compressImage(
    file: File,
    options: CompressionOptions = {},
): Promise<CompressionResult> {
    const opts = { ...DEFAULTS, ...options };
    const originalSize = file.size;

    // Load gambar ke canvas.
    const bitmap = await createImageBitmap(file);
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
        throw new Error('Canvas 2D context tidak tersedia');
    }

    // Hitung dimensi baru (preserve aspect ratio).
    let { width, height } = bitmap;

    if (width > opts.maxDimension || height > opts.maxDimension) {
        const ratio = Math.min(opts.maxDimension / width, opts.maxDimension / height);
        width = Math.round(width * ratio);
        height = Math.round(height * ratio);
    }

    canvas.width = width;
    canvas.height = height;

    // Gambar ulang ke canvas (auto-orient dari createImageBitmap).
    ctx.drawImage(bitmap, 0, 0, width, height);
    bitmap.close();

    // Convert canvas ke blob.
    const blob = await canvasToBlob(canvas, opts.mimeType, opts.quality);

    // Buat File dari blob.
    const ext = opts.mimeType === 'image/webp' ? 'webp' : opts.mimeType === 'image/png' ? 'png' : 'jpg';
    const baseName = file.name.replace(/\.[^.]+$/, '');
    const compressedFile = new File([blob], `${baseName}.${ext}`, {
        type: blob.type,
        lastModified: Date.now(),
    });

    return {
        file: compressedFile,
        originalSize,
        compressedSize: compressedFile.size,
        savings: Math.round((1 - compressedFile.size / originalSize) * 100),
        width,
        height,
    };
}

/**
 * Convert canvas ke Blob using Promise wrapper.
 */
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('Gagal mengkonversi canvas ke blob'));
                }
            },
            type,
            quality,
        );
    });
}

