#include <cstdio>
#include <cmath>

#include "vector.hpp"
#include "texture3d.hpp"
#include "list.hpp"
#include "defer.hpp"
#include "dt_pathtrace.hpp"
#include "ray_pack.hpp"


void WriteDomainAndRayPackToOBJFile(texture3D Grid, ray_pack* RayPack,
                                    const char* OBJFileName)
{
    FILE* out = fopen(OBJFileName, "w");
    if (!out) {
        fprintf(stderr, "ERROR: file %s could not be opened\n", OBJFileName);
        return;
    }
    defer {
        fclose(out);
    };

    for (float3 v : RayPack->vertices) {
        fprintf(out, "v %f %f %f\n", v.x, v.y, v.z);
    }

    // Domain Box
    float3 maxim;
    float3 minim;
    GetGridBox(Grid, minim, maxim);
    fprintf(out, "v %f %f %f\n",  maxim.x,  maxim.y,  maxim.z);
    fprintf(out, "v %f %f %f\n",  maxim.x,  maxim.y, -maxim.z);
    fprintf(out, "v %f %f %f\n",  maxim.x, -maxim.y,  maxim.z);
    fprintf(out, "v %f %f %f\n",  maxim.x, -maxim.y, -maxim.z);
    fprintf(out, "v %f %f %f\n", -maxim.x,  maxim.y,  maxim.z);
    fprintf(out, "v %f %f %f\n", -maxim.x,  maxim.y, -maxim.z);
    fprintf(out, "v %f %f %f\n", -maxim.x, -maxim.y,  maxim.z);
    fprintf(out, "v %f %f %f\n", -maxim.x, -maxim.y, -maxim.z);

    fprintf(out, "g Rays\n");
    uint32_t start = 0;
    uint32_t end;
    // all but the last sample:
    uint32_t i = 0;
    for (; i < RayPack->ray_starts.count-1; ++i) {
        end = RayPack->ray_starts[i+1];
        fprintf(out, "o Ray_%u\n", i);

        for (uint32_t j = start; j < end-1; ++j) {
            // NOTE(Felix): +1 because obj vertex ids start counting at 1
            fprintf(out, "l %u %u\n", j+1, j+2);
        }
        
        start = end;
    }
    // NOTE(Felix): the last sample;
    end = RayPack->vertices.count;
    fprintf(out, "o Ray_%u\n", i);
    printf("start %u end %u\n", start, end);
    for (uint32_t j = start; j < end-1; ++j) {
        // NOTE(Felix): +1 because obj vertex ids start counting at 1
        fprintf(out, "l %u %u\n", j+1, j+2);
    }

    end++;
    fprintf(out, "g Domain\n");
    fprintf(out, "o Domain\n");
    fprintf(out, "l %u %u\n", end+0, end+1);
    fprintf(out, "l %u %u\n", end+2, end+3);
    fprintf(out, "l %u %u\n", end+4, end+5);
    fprintf(out, "l %u %u\n", end+6, end+7);

    fprintf(out, "l %u %u\n", end+0, end+2);
    fprintf(out, "l %u %u\n", end+1, end+3);
    fprintf(out, "l %u %u\n", end+4, end+6);
    fprintf(out, "l %u %u\n", end+5, end+7);

    fprintf(out, "l %u %u\n", end+0, end+4);
    fprintf(out, "l %u %u\n", end+1, end+5);
    fprintf(out, "l %u %u\n", end+2, end+6);
    fprintf(out, "l %u %u\n", end+3, end+7);

}

int main() {
    ray_pack RayPack;
    RayPack.alloc();
    defer {
        RayPack.dealloc();
    };

    path_info PI = { };
    PI.x = {-2, -2, -2};
    PI.w = Normalize(float3{0.4,0.4,0} - PI.x);
    PI.PassNumber = 0;

    volume_info VI = { };
    VI.Grid       = ReadXYZFile("cloud-049.xyz");
    VI.Extinction = {20, 20, 20};
    VI.G          = {0.3, 0.3, 0.3};
    VI.ScatteringAlbedo = {0.9, 0.9, 0.9};

    Random::InitRNG(1);
    for (int i = 0; i < 30; ++i) {
        DTPathtrace(PI, VI, &RayPack);
    }

    WriteDomainAndRayPackToOBJFile(VI.Grid, &RayPack, "RayPack.obj");

    return 0;
}
