//External includes
#include "SDL.h"
#include "SDL_surface.h"

//Project includes
#include "Renderer.h"
#include "Maths.h"
#include "Matrix.h"
#include "Material.h"
#include "Scene.h"
#include "Utils.h"

using namespace dae;

Renderer::Renderer(SDL_Window *pWindow) :
        m_pWindow(pWindow),
        m_pBuffer(SDL_GetWindowSurface(pWindow)) {
    //Initialize
    SDL_GetWindowSize(pWindow, &m_Width, &m_Height);
    m_pBufferPixels = static_cast<uint32_t *>(m_pBuffer->pixels);

}

void Renderer::Render(Scene *pScene) const {
    Camera &camera = pScene->GetCamera();
    auto &materials = pScene->GetMaterials();
    auto &lights = pScene->GetLights();

    float apsectRatio = static_cast<float>(m_Width) / m_Height;
    float fov = tan((camera.fovAngle * (PI / 180.f)) / 2);
    for (int px{}; px < m_Width; ++px) {
        for (int py{}; py < m_Height; ++py) {
            float NDCx = ((2 * ((px + 0.5) / m_Width) - 1) * apsectRatio) * fov;
            float NDCy = (1 - 2 * ((py + 0.5) / m_Height)) * fov;


            Vector3 rayDir = Vector3{NDCx, NDCy, 1};
            rayDir.Normalize();
            Ray ray{camera.origin, rayDir};

            //set the color based on the ray direction
            ColorRGB finalColor{0.f, 0.f, 0.f};

            HitRecord closestHit{};
            Plane testPlane{{0.f, -50.f, 0.f}, {0.f, 1.f, 0.f}, 0};
//            GeometryUtils::HitTest_Plane(testPlane, ray, closestHit);
            pScene->GetClosestHit(ray, closestHit);

            if (closestHit.didHit) {
                finalColor = materials[closestHit.materialIndex]->Shade();

            }

            finalColor.MaxToOne();

            m_pBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBuffer->format,
                                                              static_cast<uint8_t>(finalColor.r * 255),
                                                              static_cast<uint8_t>(finalColor.g * 255),
                                                              static_cast<uint8_t>(finalColor.b * 255));

        }
    }

    //@END
    //Update SDL Surface
    SDL_UpdateWindowSurface(m_pWindow);
}

bool Renderer::SaveBufferToImage() const {
    return SDL_SaveBMP(m_pBuffer, "RayTracing_Buffer.bmp");
}
