// todo: kill myself
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include "include/render.h"
#include "include/matrix.h"

#define epsilon 0.4

struct Triangle {
    vec4 A, B, C;
};

static inline vec4 triangleRayIntersection(struct Triangle originaltriangle, vec4 rayDirection, vec4 rayPos) { // shameless rip from möller trumbore intersection, wikipedia
    // addition: the triangle needs to be in baryatric coordinates as per the wikipedia article, so we need to convert cartesian to baryatric coordinates
    
    struct Triangle triangle;
    
    vec4 edge1 = subVec4(triangle.B, triangle.A);
    vec4 edge2 = subVec4(triangle.C, triangle.A);
    vec4 ray_cross_e2 = crossVec4(rayDirection, edge2);
    float det = dot(edge1, ray_cross_e2);

    if (det > -epsilon && det < epsilon)
        return (vec4){0, 0, 0, -1};    // This ray is parallel to this triangle.

    float inv_det = 1.0 / det;
    vec4 s = subVec4(rayPos, triangle.A);
    float u = inv_det * dot(s, ray_cross_e2);

    if ((u < 0 && fabs(u) > epsilon) || (u > 1 && fabs(u-1) > epsilon))
    {
        //printf("did not find intersection, %d, u: %f, epsilon: %f, inv_det: %f\n", __LINE__, u, epsilon, inv_det);
        return (vec4){0, 0, 0, -1};
    }
    vec4 s_cross_e1 = crossVec4(s, edge1);
    float v = inv_det * dot(rayDirection, s_cross_e1);

    if ((v < 0 && fabs(v) > epsilon) || (u + v > 1 && fabs(u + v - 1) > epsilon)) {
        //printf("did not find intersection, %d\n", __LINE__);
        return (vec4){0, 0, 0, -1};
    }
    // At this stage we can compute t to find out where the intersection point is on the line.
    float t = inv_det * dot(edge2, s_cross_e1);

    if (t > epsilon) // ray intersection
    {
        return  addVec4(rayPos, scaleVec4(rayDirection, (vec4) {t,t,t,1}));
    }
    else { // This means that there is a line intersection but not a ray intersection.
        //printf("did not find intersection, not a triangle intersection, %d\n", __LINE__);

        return (vec4){0, 0, 0, -1};
    }
    /*
    vec4 planeNormal = crossVec4(normalizeVec4(subVec4(triangle.pointB, triangle.pointA)), normalizeVec4(subVec4(triangle.pointC, triangle.pointA)));
    float dot = dot(planeNormal, rayDirection);
    if (fabs(dot) >__MIN_DIFF) {

    }
    return -1; */
}

float Collision(struct object object, vec4 direction, vec4 srcpoint) {
    struct Triangle triangle;
    vec4 result, final;
    for (int i =0; i<object.indices_size; i+=3) {
        // get triangle
        triangle.A = (vec4) {object.vertices[i*3],object.vertices[i*3+1],object.vertices[i*3+2]};
        triangle.B = (vec4) {object.vertices[(i+1)*3],object.vertices[(i+1)*3+1],object.vertices[(i+1)*3+2]};
        triangle.C = (vec4) {object.vertices[(i+2)*3],object.vertices[(i+2)*3+1],object.vertices[(i+2)*3+2]};
        result = triangleRayIntersection(triangle, direction, srcpoint);
        if (result.w != -1) {
            printf("%lf %lf %lf %lf\n", result.x, result.y, result.z, result.w);

        }
    }
    return 0;
}