package dev.photosync.platform.impl;

import com.mojang.blaze3d.platform.NativeImage;
import dev.photosync.core.thumbnail.ThumbImage;
import dev.photosync.mcapi.render.TextureHandle;
import dev.photosync.mcapi.render.TextureSink;
import lombok.Getter;
import lombok.experimental.Accessors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.resources.Identifier;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Turns decoded pixels into something the GPU will draw.
 *
 * <p>Every upload mints its own texture id rather than reusing a slot, because
 * the browser holds many thumbnails alive at once and vanilla's texture manager
 * is the only thing that knows how to free them. The id is opaque; nothing but
 * {@link RenderAdapter} ever looks at it.
 */
public final class TextureAdapter implements TextureSink {

    private final AtomicInteger sequence = new AtomicInteger();

    @Override
    public TextureHandle upload(ThumbImage image) {
        NativeImage pixels = new NativeImage(NativeImage.Format.RGBA, image.width(), image.height(), false);
        int[] argb = image.argb();
        for (int y = 0; y < image.height(); y++) {
            int row = y * image.width();
            for (int x = 0; x < image.width(); x++) {
                // 1.21.2 renamed setPixelRGBA to setPixel and made it take ARGB
                // rather than memory-order bytes, which is what we already have.
                pixels.setPixel(x, y, argb[row + x]);
            }
        }
        return register(pixels);
    }

    @Override
    public TextureHandle decode(byte[] encoded) throws IOException {
        return register(NativeImage.read(encoded));
    }

    private Handle register(NativeImage pixels) {
        // 1.21.5 gave every GPU texture a debug label, so the id has to exist
        // before the texture does. DynamicTexture still takes ownership of the
        // image and closes it with itself; only the registration needs freeing.
        Identifier id = Identifier.fromNamespaceAndPath(
                "photosync", "thumb/" + sequence.incrementAndGet());
        DynamicTexture texture = new DynamicTexture(id::toString, pixels);
        Minecraft.getInstance().getTextureManager().register(id, texture);
        return new Handle(id, pixels.getWidth(), pixels.getHeight());
    }

    /** A registered texture, freed when the browser drops it. */
    public static final class Handle implements TextureHandle {

        @Getter
        @Accessors(fluent = true)
        private final Identifier id;

        private final int width;
        private final int height;
        private boolean released;

        private Handle(Identifier id, int width, int height) {
            this.id = id;
            this.width = width;
            this.height = height;
        }

        @Override
        public int width() {
            return width;
        }

        @Override
        public int height() {
            return height;
        }

        @Override
        public void close() {
            if (released) {
                return;
            }
            released = true;
            Minecraft.getInstance().getTextureManager().release(id);
        }
    }
}
