import { Buffer } from 'buffer';
import RNFS from 'react-native-fs';
// upng-js: used for PNG encode of CPU recolor.
import UPNG from 'upng-js';
import { renderPaintedImageOffscreen } from './paintShaderRuntime';
import { writePngBase64ToFile, writePngBytesToFile } from './exportUtils';
/**
 * CPU recolor: directly map pick codes to painted BGR colors (or copy origin).
 * Produces RGBA PNG bytes via upng-js. This is the *fallback* path when rich shader offscreen
 * is not available or fails. It produces flat colors without the editor's lighting + freq texture.
 */
function cpuRecolorToPngBytes(originBgr, pickBuffer, paintedRegions, cols, rows) {
    const pixelCount = cols * rows;
    const rgba = new Uint8Array(pixelCount * 4);
    const colorByPickCode = new Map();
    for (const [regionId, color] of paintedRegions) {
        colorByPickCode.set(regionId + 1, color);
    }
    for (let i = 0; i < pixelCount; i++) {
        const code = pickBuffer[i];
        const color = code > 0 ? colorByPickCode.get(code) : undefined;
        const d = i * 4;
        if (color) {
            rgba[d] = color.r;
            rgba[d + 1] = color.g;
            rgba[d + 2] = color.b;
            rgba[d + 3] = 255;
        }
        else {
            const s = i * 3;
            rgba[d] = originBgr[s + 2]; // RGB <- BGR
            rgba[d + 1] = originBgr[s + 1];
            rgba[d + 2] = originBgr[s];
            rgba[d + 3] = 255;
        }
    }
    const png = UPNG.encode([rgba.buffer], cols, rows, 0);
    return new Uint8Array(png);
}
/** 将上色区域导出为 recolored PNG。
 * 优先级（从好到保底）：
 * 1. exportPngBytes（调用方用 makeImageSnapshot 在高分辨率 Canvas 上捕获的完整 shader 结果）—— 推荐的“保存快照”路径，无 CPU 逐像素，无二次 drawAsImage。
 * 2. shaderTextures + render*（通过 renderPaintedImageOffscreen / drawAsImage 重建同一套 PaintShaderLayer + SkSL）。
 * 3. CPU 逐像素 recolor（flat，无光照/纹理，仅作最后兜底，保证保存不中断）。
 */
export async function compositePaintedImage(input) {
    const { originBuffer, cols, rows, pickBuffer, paintedRegions, destDir, exportPngBase64, exportPngBytes, shaderTextures, renderWidth, renderHeight, } = input;
    if (paintedRegions.size === 0) {
        throw new Error('No painted regions, cannot save');
    }
    if (pickBuffer.length !== cols * rows) {
        const msg = 'pickMap size does not match image';
        console.error('[VIZ-SAVE] composite will throw:', msg, { pickLen: pickBuffer.length, expected: cols * rows, cols, rows });
        throw new Error(msg);
    }
    if (originBuffer.length !== cols * rows * 3) {
        const msg = 'Original buffer size does not match image';
        console.error('[VIZ-SAVE] composite will throw:', msg, { originLen: originBuffer.length, expected: cols * rows * 3, cols, rows });
        throw new Error(msg);
    }
    let pngBytesForWrite;
    let pngBase64ForWrite;
    let usedSnapshot = false;
    let usedRichShader = false;
    // 1) Highest priority: pre-encoded PNG base64 from makeImageSnapshot (no extra conversion).
    if (exportPngBase64 && exportPngBase64.length > 0) {
        pngBase64ForWrite = exportPngBase64;
        usedSnapshot = true;
    }
    // 1b) Snapshot bytes fallback (legacy callers).
    else if (exportPngBytes && exportPngBytes.length > 0) {
        pngBytesForWrite = exportPngBytes;
        usedSnapshot = true;
    }
    // 2) 回退 rich：用 live 纹理 + drawAsImage 重建与编辑器一致的 shader 结果（带光照 + 频率纹理）。
    else if (shaderTextures && renderWidth && renderHeight) {
        try {
            const offImg = await renderPaintedImageOffscreen({
                originImage: shaderTextures.originImage,
                paintColorMap: shaderTextures.paintColorMap,
                lowFreqImage: shaderTextures.lowFreqImage,
                highFreqImage: shaderTextures.highFreqImage,
                width: renderWidth,
                height: renderHeight,
                showOrigin: false,
            });
            if (offImg) {
                let b64 = '';
                try {
                    const enc = offImg.encodeToBase64;
                    if (typeof enc === 'function') {
                        b64 = enc.call(offImg) || '';
                    }
                }
                catch (encErr) {
                    console.warn('[VIZ-SAVE] offscreen encodeToBase64 failed:', encErr);
                }
                if (b64 && b64.length > 0) {
                    pngBytesForWrite = new Uint8Array(Buffer.from(b64, 'base64'));
                    usedRichShader = true;
                }
                try {
                    const disp = offImg.dispose;
                    if (typeof disp === 'function')
                        disp.call(offImg);
                }
                catch { }
            }
        }
        catch (e) {
            console.warn('[VIZ-SAVE] rich shader offscreen for export failed (will fallback):', e);
        }
    }
    // 3) 最后兜底：CPU 逐像素（flat 颜色，无 editor 质感）。
    if (!pngBase64ForWrite && !pngBytesForWrite) {
        try {
            pngBytesForWrite = cpuRecolorToPngBytes(originBuffer, pickBuffer, paintedRegions, cols, rows);
        }
        catch (e) {
            throw new Error('CPU recolor PNG decoding failed');
        }
    }
    const dir = destDir ?? RNFS.CachesDirectoryPath;
    const filePath = `${dir}/painted_${Date.now()}.png`;
    try {
        if (pngBase64ForWrite) {
            await writePngBase64ToFile(filePath, pngBase64ForWrite);
        }
        else {
            await writePngBytesToFile(filePath, pngBytesForWrite);
        }
        void usedSnapshot;
        void usedRichShader;
    }
    catch (e) {
        console.error('[VIZ-SAVE] composite writeFile threw:', e, { filePath, dir });
        throw e;
    }
    return {
        filePath,
        width: cols,
        height: rows,
        paintedCount: paintedRegions.size,
    };
}
//# sourceMappingURL=compositePaintedImage.js.map