package de.blight.editor;

import com.jme3.post.SceneProcessor;
import com.jme3.profile.AppProfiler;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.texture.FrameBuffer;
import javafx.application.Platform;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * SceneProcessor: liest nach jedem JME3-Frame den Framebuffer aus und
 * schreibt die Pixel (RGBA→ARGB, Y-gespiegelt) in ein JavaFX WritableImage.
 */
public class FrameTransfer implements SceneProcessor {

    private final WritableImage image;
    private final PixelWriter   pw;
    private final int           width;
    private final int           height;

    private Renderer   renderer;
    private ByteBuffer cpuBuf;
    private byte[]     snapshot;
    private int[]      argbRow;   // Zeile für JavaFX-PixelWriter

    private final AtomicBoolean jfxBusy = new AtomicBoolean(false);

    public FrameTransfer(WritableImage image) {
        this.image  = image;
        this.pw     = image.getPixelWriter();
        this.width  = (int) image.getWidth();
        this.height = (int) image.getHeight();
    }

    @Override
    public void initialize(RenderManager rm, ViewPort vp) {
        this.renderer = rm.getRenderer();
        this.cpuBuf   = ByteBuffer.allocateDirect(width * height * 4);
        this.snapshot = new byte[width * height * 4];
        this.argbRow  = new int[width];
    }

    @Override
    public void postFrame(FrameBuffer out) {
        if (!jfxBusy.compareAndSet(false, true)) return;

        cpuBuf.clear();
        renderer.readFrameBuffer(out, cpuBuf);
        cpuBuf.rewind();
        cpuBuf.get(snapshot);

        final byte[] pixels = snapshot.clone();

        Platform.runLater(() -> {
            try {
                // GL: Y=0 unten → JavaFX: Y=0 oben  +  RGBA → 0xFFRRGGBB (int ARGB)
                PixelFormat<IntBuffer> fmt = PixelFormat.getIntArgbInstance();
                for (int y = 0; y < height; y++) {
                    int srcBase = (height - 1 - y) * width * 4;
                    for (int x = 0; x < width; x++) {
                        int r = pixels[srcBase + x * 4    ] & 0xFF;
                        int g = pixels[srcBase + x * 4 + 1] & 0xFF;
                        int b = pixels[srcBase + x * 4 + 2] & 0xFF;
                        argbRow[x] = 0xFF000000 | (r << 16) | (g << 8) | b;
                    }
                    pw.setPixels(0, y, width, 1, fmt, argbRow, 0, width);
                }
            } finally {
                jfxBusy.set(false);
            }
        });
    }

    // ── Pflichtmethoden ──────────────────────────────────────────────────────

    @Override public boolean isInitialized() { return renderer != null; }
    @Override public void reshape(ViewPort vp, int w, int h) {}
    @Override public void preFrame(float tpf) {}
    @Override public void postQueue(RenderQueue rq) {}
    @Override public void cleanup() {}
    @Override public void setProfiler(AppProfiler profiler) {}
}
