package net.ranides.assira.junit;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import static org.junit.Assert.fail;

public class ImageAssert {

    private static final int RGB_TOLERANCE = 2;

    public static void assertEquals(String expected, BufferedImage value) throws IOException {
        URL resource = ImageAssert.class.getClassLoader().getResource(expected);
        if(resource == null) {
            File outputFile = new File("target/out_" + expected.replace("/", "_"));
            ImageIO.write(value, "bmp", outputFile);

            fail("Expected resource not found: " + expected);
        }
        BufferedImage expectedImage = ImageIO.read(resource);

        int ew = expectedImage.getWidth((img, flags, x, y, width, height) -> false);
        int eh = expectedImage.getHeight((img, flags, x, y, width, height) -> false);
        int vw = value.getWidth((img, flags, x, y, width, height) -> false);
        int vh = value.getHeight((img, flags, x, y, width, height) -> false);

        int w = Math.max(ew, vw) + 20;
        int h = eh + vh + Math.max(eh, vh) + 40;

        BufferedImage view = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = view.getGraphics();
        graphics.setColor(Color.MAGENTA);
        graphics.fillRect(0,0,w,h);

        graphics.drawImage(expectedImage, 10, 10, (img, flags, x, y, width, height) -> false);
        graphics.drawImage(value, 10, eh + 20, (img, flags, x, y, width, height) -> false);

        boolean equal = true;

        for(int y=0; y<Math.min(eh, vh); y++) {
            for(int x=0; x<Math.min(ew, vw); x++) {
                Color diff;
                if(isEqual(expectedImage.getRGB(x, y), value.getRGB(x, y))) {
                    diff = Color.WHITE;
                } else {
                    diff = Color.RED;
                    equal = false;
                }
                view.setRGB(x+10, eh+vh+30 +y, diff.getRGB());
            }
        }

        if(!equal) {
            File compareFile = new File("target/" + expected.replace("/", "_"));
            File outputFile = new File("target/out_" + expected.replace("/", "_"));
            ImageIO.write(view, "bmp", compareFile);
            ImageIO.write(value, "bmp", outputFile);
            fail("Image is different than \"" + expected +"\". Look at " + compareFile.getAbsolutePath());
        }

    }

    private static boolean isEqual(int rgb1, int rgb2) {
        Color color1 = new Color(rgb1);
        Color color2 = new Color(rgb2);
        if(Math.abs(color1.getRed() - color2.getRed()) > RGB_TOLERANCE) {
            return false;
        }
        if(Math.abs(color1.getGreen() - color2.getGreen()) > RGB_TOLERANCE) {
            return false;
        }
        if(Math.abs(color1.getBlue() - color2.getBlue()) > RGB_TOLERANCE) {
            return false;
        }
        return true;
    }


}
