package testutils;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import static org.junit.jupiter.api.Assertions.*;

import electrosphere.engine.Globals;
import electrosphere.renderer.RenderingEngine;

/**
 * Utilities for comparing renders
 */
public class TestRenderingUtils {

    /**
     * The threshold at which we say the colors are 'close enough'
     */
    static final int COLOR_COMPARE_THRESHOLD = 3;
    
    /**
     * Asserts that the most recent render matches the image stored at the provided filepath
     * @param existingRenderPath The filepath of the existing render
     */
    public static void assertEqualsRender(String existingRenderPath, Runnable onFailure){
        BufferedImage testData = null;
        try {
            testData = ImageIO.read(new File(existingRenderPath));
        } catch (IOException e){
            fail("Failed to read existing image path " + existingRenderPath);
        }
        BufferedImage screenshot = RenderingEngine.defaultFramebuffer.getPixels(Globals.renderingEngine.getOpenGLState());
        //check basic data
        //
        //width
        if(testData.getWidth() != screenshot.getWidth()){
            onFailure.run();
        }
        assertEquals(testData.getWidth(), screenshot.getWidth());

        //
        //height
        if(testData.getHeight() != screenshot.getHeight()){
            onFailure.run();
        }
        assertEquals(testData.getHeight(), screenshot.getHeight());

        //
        //pixel-by-pixel check
        //
        for(int x = 0; x < testData.getWidth(); x++){
            for(int y = 0; y < testData.getHeight(); y++){

                //get from-disk rgba
                int sourceRed = testData.getRGB(x, y) & 0xff;
                int sourceGreen = (testData.getRGB(x, y) & 0xff00) >> 8;
                int sourceBlue = (testData.getRGB(x, y) & 0xff0000) >> 16;
                int sourceAlpha = (testData.getRGB(x, y) & 0xff000000) >>> 24;

                //get from-render rgba
                int renderRed = screenshot.getRGB(x, y) & 0xff;
                int renderGreen = (screenshot.getRGB(x, y) & 0xff00) >> 8;
                int renderBlue = (screenshot.getRGB(x, y) & 0xff0000) >> 16;
                int renderAlpha = (screenshot.getRGB(x, y) & 0xff000000) >>> 24;

                if(
                    Math.abs(sourceRed - renderRed) > COLOR_COMPARE_THRESHOLD ||
                    Math.abs(sourceGreen - renderGreen) > COLOR_COMPARE_THRESHOLD ||
                    Math.abs(sourceBlue - renderBlue) > COLOR_COMPARE_THRESHOLD ||
                    Math.abs(sourceAlpha - renderAlpha) > COLOR_COMPARE_THRESHOLD
                ){

                    onFailure.run();
                    String failMessage = "Colors aren't approximately the same!\n" +
                    "Color from disk:   " + sourceRed + "," + sourceGreen + "," + sourceBlue + "," + sourceAlpha + "\n" +
                    "Color from render: " + renderRed + "," + renderGreen + "," + renderBlue + "," + renderAlpha + "\n"
                    ;
                    fail(failMessage);
                }
            }
        }
    }

    /**
     * Used for saving a copy of the current render (ie for generating test data)
     * @param existingRenderPath The filepath of the existing render
     */
    public static void saveTestRender(String existingRenderPath){
        BufferedImage screenshot = RenderingEngine.defaultFramebuffer.getPixels(Globals.renderingEngine.getOpenGLState());
        try {
            ImageIO.write(screenshot, "png", new File(existingRenderPath));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
