#include "ray.h"
#include "map.h"

#include <math.h>

float v2_cross(v2 a, v2 b) {
    return fabs(a.x * b.y - a.y * b.x);
}

float v2_len(v2 a) {
    return sqrt(a.x * a.x + a.y * a.y);
}

float v2_dist(v2 a, v2 b) {
    return sqrt(v2_square_dist(a, b));
}

float v2_square_dist(v2 a, v2 b) {
    return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}

uint32_t cast_ray(v2 pos, float theta, v2* hit_pos) {

    const v2i move = {
        sign(cos(theta)),
        sign(sin(theta)),
    };

    const v2i offset = {
        move.x == -1 ? 1 : 0,
        move.y == -1 ? 1 : 0
    };
    
    const float tanc = tan(theta);
    const float cotc = tan(PIH - (theta));

    v2i posi = {
        (int)pos.x + offset.x,
        (int)pos.y + offset.y
    };

    bool fx = false;
    uint32_t vx = 0;
    float x;

    while (!fx) {
        posi.y += move.y;
        x = cotc * (posi.y - pos.y) + pos.x;
        
        if (fabs(x) - pos.x >= MAP_SIZE) break;

        vx = value((int)x, posi.y - offset.y);
        
        if (vx != 0) {
            fx = true;
        }
    }

    bool fy = false;
    uint32_t vy = 0;
    float y;

    while (!fy) {
        posi.x += move.x;
        y = tanc * (posi.x - pos.x) + pos.y;

        if (fabs(y) - pos.y >= MAP_SIZE) break;

        vy = value(posi.x - offset.x, (int)y);

        if (vy != 0) {
            fy = true;
        }
    }

    uint32_t hit;
    if (!fx && !fy) {
        hit = 0;
        hit_pos->x = pos.x + 1000 * move.x;
        hit_pos->y = pos.y + 1000 * move.y;
        return false;
    } else if (fx && !fy) {
        hit = vx;
        hit_pos->x = x;
        hit_pos->y = posi.y;
    } else if (fy && !fx) {
        hit = vy;
        hit_pos->x = posi.x;
        hit_pos->y = y;
    } else {
        const v2 posx = {x, posi.y};
        const v2 posy = {posi.x, y};
        if (v2_square_dist(posx, pos) < v2_square_dist(posy, pos)) {
            hit = vx;
            hit_pos->x = x;
            hit_pos->y = posi.y;
        } else {
            hit = vy;
            hit_pos->x = posi.x;
            hit_pos->y= y;
        }
    }

    return hit;
}