// ok cpp include
// g++ --std=c++11 test.cpp


#include "fl/gfx/downscale.h"
#include "test.h"
#include "fl/gfx/crgb.h"
#include "fl/math/xymap.h"
#include "hsv2rgb.h"


FL_TEST_CASE("downscale 2x2 to 1x1") {

    CRGB red = CRGB(255, 0, 0);
    CRGB black = CRGB(0, 0, 0);

    // We are going to simulate a 4x4 image with a 2x2 image. The source
    // image is square-cartesian while the dst image is square-serpentine.
    CRGB src[4] = {black, red, black, red};

    FL_SUBCASE("downscaleHalf from 2x2 to 1x1") {
        CRGB dst[1];
        downscaleHalf(src, 2, 2, dst);
        FL_CHECK(dst[0].r == 128);
        FL_CHECK(dst[0].g == 0);
        FL_CHECK(dst[0].b == 0);
    }

    FL_SUBCASE("downscale from 2x2 to 1x1") {
        CRGB dst[1];
        fl::XYMap srcMap = fl::XYMap::constructRectangularGrid(2, 2);
        fl::XYMap dstMap = fl::XYMap::constructRectangularGrid(1, 1);

        downscale(src, srcMap, dst, dstMap);
        FL_CHECK(dst[0].r == 128);
        FL_CHECK(dst[0].g == 0);
        FL_CHECK(dst[0].b == 0);
    }


    FL_SUBCASE("4x4 rectangle to 2x2 serpentine") {
        // We are going to simulate a 4x4 image with a 2x2 image. The source
        // image is square-cartesian while the dst image is square-serpentine.

        CRGB src[16] = {// Upper left red, lower right red, upper right black,
                        // lower left black
                        red,   red,   black, black, red,   red,   black, black,
                        black, black, red,   red,   black, black, red,   red};

        CRGB dst[4];

        fl::XYMap srcMap = fl::XYMap::constructRectangularGrid(4, 4);
        fl::XYMap dstMap = fl::XYMap::constructSerpentine(2, 2);

        downscale(src, srcMap, dst, dstMap);

        CRGB lowerLeft = dst[dstMap.mapToIndex(0, 0)];
        CRGB lowerRight = dst[dstMap.mapToIndex(1, 0)];
        CRGB upperLeft = dst[dstMap.mapToIndex(0, 1)];
        CRGB upperRight = dst[dstMap.mapToIndex(1, 1)];

        FL_REQUIRE(lowerLeft == red);
        FL_REQUIRE(lowerRight == black);
        FL_REQUIRE(upperLeft == black);
        FL_REQUIRE(upperRight == red);
    }

}

FL_TEST_CASE("downscale 3x3 to 2x2") {
    CRGB red = CRGB(255, 0, 0);
    CRGB black = CRGB(0, 0, 0);

    // Create a 3x3 checkerboard pattern:
    CRGB src[9];
    src[0] = red;
    src[1] = black;
    src[2] = red;
    src[3] = black;
    src[4] = red;
    src[5] = black;
    src[6] = red;
    src[7] = black;
    src[8] = red;

    CRGB dst[4];  // 2x2 result

    fl::XYMap srcMap = fl::XYMap::constructRectangularGrid(3, 3);
    fl::XYMap dstMap = fl::XYMap::constructRectangularGrid(2, 2);

    downscale(src, srcMap, dst, dstMap);

    for (int i = 0; i < 4; ++i) {
        FL_DINFO("Dst[" << i << "]: " << dst[i]);
        FL_CHECK(dst[i] == CRGB(142, 0, 0));  // Averaged color
    }
}


FL_TEST_CASE("downscale 11x11 to 2x2") {
    CRGB red = CRGB(255, 0, 0);
    CRGB black = CRGB(0, 0, 0);

    // Create a 3x3 checkerboard pattern:
    CRGB src[11*11];
    for (int i = 0; i < 11*11; ++i) {
        src[i] = (i % 2 == 0) ? red : black;
    }

    CRGB dst[4];  // 2x2 result

    fl::XYMap srcMap = fl::XYMap::constructRectangularGrid(11, 11);
    fl::XYMap dstMap = fl::XYMap::constructRectangularGrid(2, 2);

    downscale(src, srcMap, dst, dstMap);

    for (int i = 0; i < 4; ++i) {
        FL_DINFO("Dst[" << i << "]: " << dst[i]);
        FL_CHECK(dst[i] == CRGB(129, 0, 0));  // Averaged color
    }
}

// Grouped tests
#include "tests/fl/gfx/splat.hpp"
FL_TEST_FILE(FL_FILEPATH) {

} // FL_TEST_FILE
