#include <iostream>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

//#include <imgui.h>
//#include <imgui_impl_glfw.h>
//#include <imgui_impl_opengl3.h>

#define WINDOW_WIDTH  1280
#define WINDOW_HEIGHT 720

#include <engine/io/Window.hpp>
#include <engine/graphics/back/cameras/View.hpp>
#include <engine/graphics/front/object/Image.hpp>
#include <engine/graphics/front/group/ImageGroup.hpp>
#include <engine/graphics/front/engine/Renderer.hpp>
#include <engine/graphics/front/engine/Engine.hpp>
#include <engine/graphics/errors.hpp>

const float i_x =  1.f;
const float i_y =  0.5f;
const float j_x = -1.f;
const float j_y =  0.5f;

glm::vec2 to_screen_coordinate(const glm::vec2 & tile, float w, float h, float layer = 0.0f) {
    return {
        (tile.x + layer) * i_x * 0.5f * w + (tile.y + layer) * j_x * 0.5f * w,
        (tile.x + layer) * i_y * 0.5f * h + (tile.y + layer) * j_y * 0.5f * h
    };
}

int main(int argc, const char * argv[]) {
    try {
        //? Window
        megu::Window window;
        window.open("Isometric Window", 360, 360);
        megu::error::opengl_error::check();

        std::cout << "Window Inited" << std::endl;

        //? Group
        megu::ImageGroup group;
        megu::ImageGroup group_2;
       
        std::cout << "Group Inited" << std::endl;

        //? Image 1
        std::vector<int> map = {
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
            1, 1, 2, 3, 4, 5, 6, 7, 8, 9,
            2, 2, 2, 3, 4, 5, 6, 7, 8, 9,
            3, 3, 3, 3, 4, 5, 6, 7, 8, 9,
            4, 4, 4, 4, 4, 5, 6, 7, 8, 9,
            5, 5, 5, 5, 5, 5, 6, 7, 8, 9,
            6, 6, 6, 6, 6, 6, 6, 7, 8, 9,
            7, 7, 7, 7, 7, 7, 7, 7, 8, 9,
            8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
            9, 9, 9, 9, 9, 9, 9, 9, 9, 9,

        };

        size_t x = 0;
        size_t y = 0;

        std::vector<std::unique_ptr<megu::Image>> images;

        megu::Texture texture_0;
        texture_0.store(megu::TextureBuffer("assets/textures/Cube_Red.png"));

        megu::Texture texture_1;
        texture_1.store(megu::TextureBuffer("assets/textures/Cube_Green.png"));

        megu::Texture texture_2;
        texture_2.store(megu::TextureBuffer("assets/textures/Cube_Blue.png"));

        megu::Texture texture_3;
        texture_3.store(megu::TextureBuffer("assets/textures/Cube_Yellow.png"));

        for(auto id : map) {
            if(x == 10) {
                x = 0;
                ++y;
            }


            if(id != 0) {
                switch (id % 4) {
                    case 1:
                        images.push_back(std::make_unique<megu::Image>(texture_1));
                        break;

                    case 2:
                        images.push_back(std::make_unique<megu::Image>(texture_2));
                        break;

                    case 3:
                        images.push_back(std::make_unique<megu::Image>(texture_3));
                        break;

                    default:
                        images.push_back(std::make_unique<megu::Image>(texture_0));
                        break;
                }
                
                glm::vec2 pos = to_screen_coordinate({x, y}, 32.f, 32.f, static_cast<float>(id)-3.f);

                images.back()->setPosition({pos.x + window.width()/2, pos.y + window.height()/8});
            }
            
            ++x;
        }

        for(auto & i : images) {
            group.add(*i);
            i.get()->setSize({32.f, 32.f});
        }

        std::cout << "Images 1 Inited" << std::endl;

        //? Image 2
        std::vector<int> map_2 = {
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        };

        size_t x_2 = 0;
        size_t y_2 = 0;

        std::vector<std::unique_ptr<megu::Image>> images_2;

        megu::Texture texture_4;
        texture_4.store(megu::TextureBuffer("assets/textures/Cube_White.png"));

        for(auto id : map_2) {
            if(x_2 == 10) {
                x_2 = 0;
                ++y_2;
            }
                
            images_2.push_back(std::make_unique<megu::Image>(texture_4));
            glm::vec2 pos = to_screen_coordinate({x_2, y_2}, 32.f, 32.f, 0.f);
            images_2.back()->setPosition({pos.x + window.width()/2 - 16.f, pos.y + window.height()/4});
            
            ++x_2;
        }

        for(auto & i : images_2) {
            group_2.add(*i);
            i.get()->setSize({32.f, 32.f});
        }

        std::cout << "Images 2 Inited" << std::endl;

        //? ImGui
        //ImGui::CreateContext();
        //ImGui_ImplOpenGL3_Init();
        //ImGui_ImplGlfw_InitForOpenGL(window.ptr(), true);

        //? Engines
        megu::GraphicEngine engine(window);
        megu::Renderer basic_renderer(360, 360);

        engine.push(0, basic_renderer);

        engine.push(0, 0, group);
        //engine.push(0, 0, group_2);

        //? Render Loop
        std::cout << "Render Loop Begin !" << std::endl;
        glm::vec2 xy = {0, 0};

        double previousTime = megu::Window::Time();
        int frameCount = 0;

        while(window.isOpen()) {
            double currentTime = megu::Window::Time();
            frameCount++;

            if(currentTime - previousTime >= 1.0) {
                window.setTitle(std::to_string(frameCount));

                frameCount = 0;
                previousTime = currentTime;
            }

            window.pollEvents();
            engine.step();
        }
        std::cout << "Render Loop End !" << std::endl;
    }
    catch(std::exception & error) {
        std::cerr << error.what() << std::endl;
    }

    return EXIT_SUCCESS;
}