/**
 * Client-side image resize/compress before POST to upload API.
 * Client optimization reduces payload before ImgBB (up to 32 MB per their API); smaller uploads are faster.
 */

export const UPLOAD_PROFILES = {
    product: { maxWidth: 1200, maxHeight: 1200, quality: 0.85, maxInputBytes: 30 * 1024 * 1024 },
    banner: { maxWidth: 1920, maxHeight: 1920, quality: 0.82, maxInputBytes: 40 * 1024 * 1024 },
    category: { maxWidth: 800, maxHeight: 800, quality: 0.85, maxInputBytes: 25 * 1024 * 1024 },
    logo: { maxWidth: 640, maxHeight: 640, quality: 0.88, maxInputBytes: 15 * 1024 * 1024 },
    smallBanner: { maxWidth: 1000, maxHeight: 600, quality: 0.82, maxInputBytes: 20 * 1024 * 1024 },
    size_chart: { maxWidth: 1600, maxHeight: 2400, quality: 0.85, maxInputBytes: 30 * 1024 * 1024 },
};

const PASSTHROUGH_TYPES = new Set(['image/svg+xml', 'image/gif']);

function canvasToBlob(canvas, type, quality) {
    return new Promise((resolve) => {
        canvas.toBlob((blob) => resolve(blob), type, quality);
    });
}

/**
 * Encode canvas to WebP, then JPEG, then PNG.
 * @param {HTMLCanvasElement} canvas
 * @param {number} quality 0..1
 */
async function encodeCanvas(canvas, quality) {
    let blob = await canvasToBlob(canvas, 'image/webp', quality);
    if (blob && blob.size > 0) return { blob, mime: 'image/webp', ext: '.webp' };
    blob = await canvasToBlob(canvas, 'image/jpeg', quality);
    if (blob && blob.size > 0) return { blob, mime: 'image/jpeg', ext: '.jpg' };
    blob = await canvasToBlob(canvas, 'image/png');
    if (blob && blob.size > 0) return { blob, mime: 'image/png', ext: '.png' };
    return null;
}

/**
 * @param {File} file
 * @param {string|object} profileKeyOrOpts profile name or overrides merged onto `product` defaults
 * @returns {Promise<File>}
 */
export async function optimizeImageForUpload(file, profileKeyOrOpts = 'product') {
    const base =
        typeof profileKeyOrOpts === 'string'
            ? { ...(UPLOAD_PROFILES[profileKeyOrOpts] || UPLOAD_PROFILES.product) }
            : { ...UPLOAD_PROFILES.product, ...profileKeyOrOpts };
    const maxWidth = base.maxWidth ?? 1200;
    const maxHeight = base.maxHeight ?? 1200;
    const quality = typeof base.quality === 'number' ? base.quality : 0.85;
    const maxInputBytes = base.maxInputBytes ?? 30 * 1024 * 1024;

    if (!file || !(file instanceof Blob)) {
        throw new Error('No file selected.');
    }
    const type = (file.type || '').toLowerCase();
    if (!type.startsWith('image/')) {
        throw new Error('Please choose an image file.');
    }
    if (file.size > maxInputBytes) {
        const mb = Math.round(maxInputBytes / (1024 * 1024));
        throw new Error(`Image is too large (max ~${mb} MB for this slot).`);
    }

    if (PASSTHROUGH_TYPES.has(type)) {
        return file instanceof File ? file : new File([file], 'image', { type });
    }

    let bitmap;
    try {
        bitmap = await createImageBitmap(file);
    } catch {
        throw new Error(
            'Could not read this image. Try JPEG or PNG, or on iPhone export as JPEG before uploading.'
        );
    }

    const sw = bitmap.width;
    const sh = bitmap.height;
    const scale = Math.min(1, maxWidth / sw, maxHeight / sh);
    const dw = Math.max(1, Math.round(sw * scale));
    const dh = Math.max(1, Math.round(sh * scale));

    const canvas = document.createElement('canvas');
    canvas.width = dw;
    canvas.height = dh;
    const ctx = canvas.getContext('2d', { alpha: true });
    if (type === 'image/jpeg') {
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, dw, dh);
    }
    ctx.drawImage(bitmap, 0, 0, dw, dh);
    bitmap.close();

    let q = quality;
    let encoded = await encodeCanvas(canvas, q);
    const minQ = 0.52;
    while (encoded && encoded.mime === 'image/webp' && encoded.blob.size > file.size * 1.05 && q > minQ + 0.02) {
        q -= 0.06;
        encoded = await encodeCanvas(canvas, q);
    }

    if (!encoded || !encoded.blob) {
        throw new Error('Could not compress image in this browser.');
    }

    if (encoded.blob.size >= file.size && scale >= 1) {
        return file instanceof File ? file : new File([file], file.name || 'image', { type: file.type });
    }

    const baseName = String(file.name || 'image').replace(/\.[^.]+$/, '');
    const outName = baseName + encoded.ext;
    return new File([encoded.blob], outName, { type: encoded.mime, lastModified: Date.now() });
}

/*
 * QA: try product PNG (alpha), large JPEG (4MP+), banner wide PNG; Chrome + Safari.
 * Tune UPLOAD_PROFILES maxWidth/quality if uploads feel soft or still too heavy.
 * v2: enforce max dimensions in upload API (GD/ImageMagick) as a safety net.
 */
