// =============================================================================
// Image Worker
// Handles image conversions using ImageMagick WASM
// Note: heic2any doesn't work in workers (requires window), so HEIC is handled
// by the main thread adapter using Canvas API or separate solution
// =============================================================================

import * as Comlink from 'comlink';
import {
  initializeImageMagick,
  ImageMagick,
  MagickGeometry,
  type IMagickImage,
} from '@imagemagick/magick-wasm';
import type { ImageFormat } from '../core/types';
import { IMAGE_FORMAT_MAP, FORMAT_TO_MIME, LOSSY_IMAGE_FORMATS } from '../core/constants';

let magickInitialized = false;
let initPromise: Promise<void> | null = null;

async function ensureMagickInitialized(): Promise<void> {
  if (magickInitialized) return;
  if (initPromise) return initPromise;

  initPromise = (async () => {
    // Use local WASM from public folder (works offline)
    const response = await fetch('/wasm/magick.wasm');
    const wasmBytes = new Uint8Array(await response.arrayBuffer());
    
    await initializeImageMagick(wasmBytes);
    magickInitialized = true;
    console.log('[ImageWorker] ImageMagick WASM initialized');
  })();

  return initPromise;
}

// -----------------------------------------------------------------------------
// Image Processor (DRY: Handles Read → Modify → Write lifecycle)
// -----------------------------------------------------------------------------

/**
 * Generic image processor that handles I/O and accepts an operation callback.
 * The operation callback receives the image for manipulation (resize, quality, etc.)
 */
async function processImage(
  buffer: ArrayBuffer,
  outputFormat: ImageFormat,
  operation: (image: IMagickImage) => void
): Promise<Blob> {
  await ensureMagickInitialized();
  const inputData = new Uint8Array(buffer);
  const magickFormat = IMAGE_FORMAT_MAP[outputFormat];
  
  if (!magickFormat) {
    throw new Error(`Unsupported output format: ${outputFormat}`);
  }

  return new Promise((resolve, reject) => {
    try {
      ImageMagick.read(inputData, (image) => {
        // Run the specific operation (resize, quality change, etc.)
        operation(image);

        // Standard output handling
        image.write(magickFormat, (data) => {
          // Clone buffer to detach from SharedArrayBuffer
          const resultBuffer = new ArrayBuffer(data.length);
          new Uint8Array(resultBuffer).set(data);
          resolve(new Blob([resultBuffer], { type: FORMAT_TO_MIME[outputFormat] }));
        });
      });
    } catch (error) {
      reject(error);
    }
  });
}

// -----------------------------------------------------------------------------
// Image Converter API
// -----------------------------------------------------------------------------

const imageConverter = {
  /**
   * Initialize the worker (can be called early to warm up)
   */
  async init(): Promise<boolean> {
    try {
      await ensureMagickInitialized();
      return true;
    } catch (error) {
      console.error('[ImageWorker] Init failed:', error);
      return false;
    }
  },

  /**
   * Convert image using ImageMagick WASM
   */
  async convertImage(
    arrayBuffer: ArrayBuffer,
    _inputFormat: ImageFormat,
    outputFormat: ImageFormat,
    quality: number = 85
  ): Promise<Blob> {
    return processImage(arrayBuffer, outputFormat, (image) => {
      // ICO format has max size of 256x256
      if (outputFormat === 'ico' && (image.width > 256 || image.height > 256)) {
        const geometry = new MagickGeometry(256, 256);
        geometry.ignoreAspectRatio = false;
        image.resize(geometry);
      }

      // Set quality for lossy formats
      if (LOSSY_IMAGE_FORMATS.includes(outputFormat)) {
        image.quality = quality;
      }
    });
  },

  /**
   * Resize image using ImageMagick
   */
  async resizeImage(
    arrayBuffer: ArrayBuffer,
    width: number,
    height: number,
    outputFormat: ImageFormat,
    quality: number = 85
  ): Promise<Blob> {
    return processImage(arrayBuffer, outputFormat, (image) => {
      // Resize operation
      const geometry = new MagickGeometry(width, height);
      geometry.ignoreAspectRatio = false;
      image.resize(geometry);

      // Set quality for lossy formats
      if (LOSSY_IMAGE_FORMATS.includes(outputFormat)) {
        image.quality = quality;
      }
    });
  },
};

Comlink.expose(imageConverter);

export type ImageConverterWorker = typeof imageConverter;