package org.engine;

import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

public class Display implements AutoCloseable {
    private final long handle;
    private final Dimension size;
    private GLFWFramebufferSizeCallback framebufferSizeCallback;
    private volatile boolean requiredRebuild;

    public Display(BufferedImage icon) {
        this.size = Toolkit.getDefaultToolkit().getScreenSize();
        this.size.width >>= 1;
        this.size.height >>= 1;


        GLFW.glfwDefaultWindowHints();
        GLFW.glfwWindowHint(131076, 0);
        GLFW.glfwWindowHint(131075, 1);

        this.handle = GLFW.glfwCreateWindow(this.size.width, this.size.height, "RTX-GYTEBOT", 0L, 0L);

        setWindowIcon(icon);

        if (this.handle == 0L) {
            throw new AssertionError("Failed to create the GLFW window!");
        }

        orientateWindow();

        GLFW.glfwMakeContextCurrent(this.handle);


        Exception exception1 = null, exception2 = null;
        try {
            MemoryStack frame = MemoryStack.stackPush();
            try {
                IntBuffer framebufferSize = frame.mallocInt(2);


                GLFW.nglfwGetFramebufferSize(this.handle, MemoryUtil.memAddress(framebufferSize), MemoryUtil.memAddress(framebufferSize) + 4L);


                this.size.width = framebufferSize.get(0);
                this.size.height = framebufferSize.get(1);
            } finally {
                if (frame != null) frame.close();
            }
        } finally {
            exception2 = null;
            if (exception1 == null) {
                exception1 = exception2;
            } else if (exception1 != exception2) {
                exception1.addSuppressed(exception2);
            }
        }

    }

    private void setWindowIcon(BufferedImage icon) {
        byte[] data = ((DataBufferByte) icon.getRaster().getDataBuffer()).getData();

        ByteBuffer pixels = BufferUtils.createByteBuffer(data.length);
        pixels.put(data);
        pixels.flip();

        GLFWImage.Buffer gb = GLFWImage.create(1);
        GLFWImage image = GLFWImage.create().set(icon.getWidth(), icon.getHeight(), pixels);

        gb.put(0, image);

        GLFW.glfwSetWindowIcon(this.handle, gb);
    }


    private void orientateWindow() {
        int[] left = new int[1];
        int[] top = new int[1];
        int[] right = new int[1];
        int[] bottom = new int[1];

        GLFW.glfwGetWindowFrameSize(this.handle, left, top, right, bottom);

        this.size.width = this.size.width - left[0] - right[0];
        this.size.height = this.size.height - bottom[0] - top[0];

        GLFW.glfwSetWindowSize(this.handle, this.size.width, this.size.height);

        GLFW.glfwSetWindowPos(this.handle, right[0], top[0]);
    }

    public final void close() {
        //this.framebufferSizeCallback.free();
        GLFW.glfwDestroyWindow(this.handle);
    }


    public final void show() {
        GLFW.glfwShowWindow(this.handle);
    }


    public final boolean shouldNotClose() {
        return !GLFW.glfwWindowShouldClose(this.handle);
    }


    public final void swapBuffers() {
        GLFW.glfwSwapBuffers(this.handle);
    }


    public final long getWindowHandle() {
        return this.handle;
    }


    public final int getWidth() {
        return this.size.width;
    }


    public final int getHeight() {
        return this.size.height;
    }


    public final Dimension getSize() {
        return this.size;
    }


    public boolean wasScaled() {
        if (this.requiredRebuild) {


            this.requiredRebuild = false;
            return true;
        }


        return false;
    }
}
