import Input from "@common/input";

export function loadImageData(dataView: DataView, pointer: number) {
    const width = dataView.getUint16(pointer + 0, true);
    const height = dataView.getUint16(pointer + 2, true);

    const dataPtr = dataView.getUint32(pointer + 4, true);
    const imageBuffer = new Uint8ClampedArray(dataView.buffer, dataPtr, width * height * 4);
    // @ts-ignore — Bun's Uint8ClampedArray typedef incorrectly narrows the buffer type
    const imageData = new ImageData(imageBuffer, width, height);

    return imageData;
}

export function createCanvas(width: number, height: number) {
    const canvas = document.createElement('canvas');

    canvas.width = width;
    canvas.height = height;
    canvas.style.width = '100dvw';
    canvas.style.height = '100dvh';
    canvas.style.objectFit = 'contain';
    canvas.style.imageRendering = 'pixelated';

    document.body.style.display = 'flex';
    document.body.style.justifyContent = 'center';
    document.body.style.alignItems = 'center';
    document.body.append(canvas);

    Input.setMainCanvas(canvas);

    return canvas;
}

interface WasmModule {
    data: DataView;
    canvas_init?: (width: number, height: number) => number;
    canvas_frame?: () => void;
}

export function createWasmCanvas(module: WasmModule, width: number = 0, height: number = 0) {
    const pointer = module.canvas_init?.(width, height);

    if (pointer) {
        const imageData = loadImageData(module.data, pointer);
        const canvas = createCanvas(imageData.width, imageData.height);
        const context = canvas.getContext('2d');

        if (context && typeof module.canvas_frame === 'function') {
            const frame = () => {
                module.canvas_frame?.();
                context.putImageData(imageData, 0, 0);
                requestAnimationFrame(frame);
            };
            frame();
        }

        return canvas;
    }
    console.error(`[createWasmCanvas] WASM init's function should return pointer to image data`);
    return createCanvas(width, height);
}

export function getImageData(image: HTMLImageElement): ImageData {
    const canvas = document.createElement('canvas');
    canvas.width = image.naturalWidth;
    canvas.height = image.naturalHeight;
    const ctx = canvas.getContext('2d')!;
    ctx.drawImage(image, 0, 0);
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

    return imageData;
}


export const getPixel = (imageData: ImageData, x: number, y: number): [number, number, number, number] => {
    const index = (y * imageData.width + x) * 4;
    return [
        imageData.data[index + 0],
        imageData.data[index + 1],
        imageData.data[index + 2],
        imageData.data[index + 3],
    ];
}

export const getPixelInt = (imageData: ImageData, x: number, y: number): number => {
    const index = (y * imageData.width + x) * 4;
    return (
        imageData.data[index + 0] << 24 | 
        imageData.data[index + 1] << 16 | 
        imageData.data[index + 2] << 8 | 
        imageData.data[index + 3] << 0
    );
}

export const setPixel = (imageData: ImageData, x: number, y: number, color: [number, number, number, number] | number) => {
    const index = (y * imageData.width + x) * 4;
    if (Array.isArray(color)) {
        imageData.data[index + 0] = color[0];
        imageData.data[index + 1] = color[1];
        imageData.data[index + 2] = color[2];
        imageData.data[index + 3] = color[3];
    } else {
        const index = (y * imageData.width + x) * 4;
        imageData.data[index + 0] = (color >> 24) & 0xFF;
        imageData.data[index + 1] = (color >> 16) & 0xFF;
        imageData.data[index + 2] = (color >> 8) & 0xFF;
        imageData.data[index + 3] = color & 0xFF;
    }
}
