#include "MainWindow.hpp"
#include "fastmath.hpp"
#include "plane.hpp"
#include "polygon.hpp"
#include "renderer.hpp"
#include "rendertarget.hpp"
#include "testModel.hpp"
#include <QApplication>
#include <chrono>
#include <functional>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define HIGHT 64
#define WIDTH 64

#define FAA_FAC 2
#define RHIGHT ((int)(HIGHT * FAA_FAC))
#define RWIDTH ((int)(WIDTH * FAA_FAC))

char *drawToString(unsigned short *img) {
    char *textImg = (char *)malloc(200000 * sizeof(char));
    // strcat(textImg,"\e[1;1H\e[2J"); --clear
    for (int y = 0; y < HIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            // printf("%d,%d\n",x,y);
            char buff[20];
            unsigned short val = 0;
            int my = y * FAA_FAC;
            int mx = x * FAA_FAC;
            val += img[my * RWIDTH + mx];
            val += img[my * RWIDTH + mx + 1];
            val += img[(my + 1) * RWIDTH + mx];
            val += img[(my + 1) * RWIDTH + mx + 1];
            sprintf(buff, "\033[38;5;%dm██\033[0m", 232 + val / 4);
            strcat(textImg, buff);
        }
        strcat(textImg, "\n");
    }
    return textImg;
}

int main(int argc, char *argv[]) {
    Rendertarget target(128, 128);
    Renderer renderer;
    renderer.target = &target;

    std::chrono::steady_clock::time_point begin =
        std::chrono::steady_clock::now();
    renderer.render(&testModel, mat4::translation(vec3(0.0f, -1.0f, 5.0f)) *
                                    mat4::rotateOnY(-1.5707963267948966f));
    std::chrono::steady_clock::time_point end =
        std::chrono::steady_clock::now();

    std::cout << "Time difference = "
              << std::chrono::duration_cast<std::chrono::milliseconds>(end -
                                                                       begin)
                     .count()
              << "[ms]" << std::endl;

    uint8_t *pixel = new uint8_t[64 * 64 * 3];
    /*for (int i = 0; i < 64 * 64 * 3; i++) {
        pixel[i] = target.pixels[i].i >> SHIFT_AMOUNT;
    }*/
    std::function<void(int, uint32_t *)> addTo = [&target](int start,
                                                           uint32_t *arr) {
        for (int c = 0; c < 3; c++) {
            arr[c] += target.pixels[start + c];
        }
    };
    vec3 pos;

    QApplication a(argc, argv);
    MainWindow widget;
    widget.setWindowTitle("SoftwareRenderer");

    // display.setPixmap(QPixmap::fromImage(img).scaled(widget.size()));
    auto keyEvent = [&pos](QKeyEvent *e) {
        decimal step = decimal(0.5);
        switch (e->key()) {
        case Qt::Key_W:
            pos.z() += step;
            break;
        case Qt::Key_S:
            pos.z() -= step;
            break;
        case Qt::Key_A:
            pos.x() += step;
            break;
        case Qt::Key_D:
            pos.x() -= step;
            break;
        }
    };
    widget.keyDownCallBack = keyEvent;

    float rot = 0.f;
    std::function<void()> renderLoop = [&addTo, &target, &pixel, &renderer,
                                        &widget, &rot, &pos]() {
        std::chrono::steady_clock::time_point begin =
            std::chrono::steady_clock::now();

        target.clearDepth();
        target.clearTarget();

        // renderer.render(&testModel, mat4::translation(vec3(0.0f,
        // -1.0f, 5.0f)) *
        //                                 mat4::rotateOnY(rot));
        // renderer.render(&testModel, mat4::translation(vec3(1.0f,
        // -1.0f, 7.0f)) *
        //                                 mat4::rotateOnY(rot));
        renderer.render(&plane, mat4::translation(pos));
        std::chrono::steady_clock::time_point end =
            std::chrono::steady_clock::now();

        std::cout << "Time difference = "
                  << std::chrono::duration_cast<std::chrono::milliseconds>(
                         end - begin)
                         .count()
                  << "[ms]" << std::endl;

        for (int x = 0; x < 64; x++) {
            for (int y = 0; y < 64; y++) {
                uint32_t result[3] = {};
                addTo((target.width * y * 2 + x * 2) * 3, result);
                addTo((target.width * (y * 2 + 1) + x * 2) * 3, result);
                addTo((target.width * y * 2 + (x * 2 + 1)) * 3, result);
                addTo((target.width * (y * 2 + 1) + (x * 2 + 1)) * 3, result);
                for (int c = 0; c < 3; c++) {
                    pixel[(WIDTH * (WIDTH - y - 1) + WIDTH - x - 1) * 3 + c] =
                        result[c] >> 2;
                }
            }
        }
        // QImage img((unsigned char *)pixel, 64, 64, QImage::Format_RGB888);
        widget.updateLabel(pixel);

        rot += 0.1f;
    };
    renderLoop();
    widget.show();
    QTimer timer;
    timer.setInterval(20);
    timer.start();
    QObject::connect(&timer, &QTimer::timeout, &widget, renderLoop);
    return a.exec();
}
