// Background Removal Worker using briaai/RMBG-1.4
// Using @huggingface/transformers v3

import { AutoModel, AutoProcessor, RawImage, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.5.1';

console.log('[BG-Processor Worker] Script loaded from /public');

// Configuration
env.allowLocalModels = false;
env.useBrowserCache = true;
// Force WASM backend (more compatible)
env.backends.onnx.wasm.proxy = false;

let model = null;
let processor = null;

/**
 * Load the RMBG-1.4 model (WASM only for compatibility)
 */
const loadModel = async () => {
    if (!model) {
        console.log('[BG-Processor Worker] Loading briaai/RMBG-1.4 model (WASM)...');
        model = await AutoModel.from_pretrained('briaai/RMBG-1.4', {
            device: 'wasm',
            dtype: 'fp32',
        });
        processor = await AutoProcessor.from_pretrained('briaai/RMBG-1.4');
        console.log('[BG-Processor Worker] Model loaded successfully.');
    }
    return { model, processor };
};

/**
 * Apply the alpha mask to the original image
 */
const applyMask = async (originalBlob, maskData, width, height) => {
    const bitmap = await createImageBitmap(originalBlob);

    const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
    const ctx = canvas.getContext('2d');
    if (!ctx) throw new Error("No Canvas context");

    // Draw original image
    ctx.drawImage(bitmap, 0, 0);

    // Get image data
    const imageData = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
    const data = imageData.data;

    // Create mask canvas at model output size
    const maskCanvas = new OffscreenCanvas(width, height);
    const maskCtx = maskCanvas.getContext('2d');
    const maskImageData = maskCtx.createImageData(width, height);

    // Convert model output to grayscale image
    for (let i = 0; i < maskData.length; i++) {
        const val = Math.round(Math.max(0, Math.min(1, maskData[i])) * 255);
        maskImageData.data[i * 4] = val;
        maskImageData.data[i * 4 + 1] = val;
        maskImageData.data[i * 4 + 2] = val;
        maskImageData.data[i * 4 + 3] = 255;
    }
    maskCtx.putImageData(maskImageData, 0, 0);

    // Scale mask to original size
    const scaledMaskCanvas = new OffscreenCanvas(bitmap.width, bitmap.height);
    const scaledMaskCtx = scaledMaskCanvas.getContext('2d');
    scaledMaskCtx.drawImage(maskCanvas, 0, 0, bitmap.width, bitmap.height);
    const scaledMaskData = scaledMaskCtx.getImageData(0, 0, bitmap.width, bitmap.height);

    // Apply mask as alpha
    for (let i = 0; i < data.length; i += 4) {
        data[i + 3] = scaledMaskData.data[i]; // Use R channel as alpha
    }

    ctx.putImageData(imageData, 0, 0);
    return await canvas.convertToBlob({ type: 'image/png' });
};

self.onmessage = async (e) => {
    const { type, id, imageBlob } = e.data;

    if (type === 'ping') {
        self.postMessage({ type: 'pong' });
        return;
    }

    if (!imageBlob) return;

    console.log(`[BG-Processor Worker] Received request for ${id}`);

    try {
        const { model, processor } = await loadModel();

        // Convert blob to RawImage
        const url = URL.createObjectURL(imageBlob);
        const image = await RawImage.fromURL(url);
        URL.revokeObjectURL(url);

        console.log('[BG-Processor Worker] Running inference...');

        // Process image
        const { pixel_values } = await processor(image);

        // Run model
        const { output } = await model({ input: pixel_values });

        // Get mask data - output is a Tensor
        const maskData = output.data;
        const [batch, channels, height, width] = output.dims;

        console.log(`[BG-Processor Worker] Mask dims: ${width}x${height}`);
        console.log('[BG-Processor Worker] Applying mask...');

        const processedBlob = await applyMask(imageBlob, maskData, width, height);

        self.postMessage({ id, status: 'success', blob: processedBlob });
        console.log(`[BG-Processor Worker] Successfully processed ${id}`);
    } catch (err) {
        console.error(`[BG-Processor Worker] Processing Error (${id}):`, err);
        self.postMessage({ id, status: 'error', error: err.message });
    }
};
