#ifndef PROTOTYPE_1_SRC_L1_MARIE_GEOM_ALG_UTILS_H
#define PROTOTYPE_1_SRC_L1_MARIE_GEOM_ALG_UTILS_H

#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <float.h>
#include <math.h>
#include "../../../gen/l1/geom.h"
#include "../core/util.h"

/* float size check and IEEE‑754 binary32 characteristic checks */
_Static_assert(sizeof(float) == 4,
               "This code assumes 32‑bit floats");
#if defined(__STDC_IEC_559__)        /* implementation claims IEC 60559 */
_Static_assert(__STDC_IEC_559__, "Implementation is not IEC 60559");
#else
/* Fall back to value‑based checks: radix 2, 24‑bit mantissa, exponent ranges.
   These values are unique to binary32 among the formats in actual use. */
_Static_assert(FLT_RADIX == 2,           "Non‑binary radix");
_Static_assert(FLT_MANT_DIG == 24,       "Float is not binary32");
_Static_assert(FLT_MAX_EXP == 128,       "Float is not binary32");
_Static_assert(FLT_MIN_EXP == -125,      "Float is not binary32");
#endif

uint32_t marie_pun_float2u32(float f) {
    uint32_t u;
    memcpy(&u, &f, sizeof u);
    return u;
}

bool marie_same_dir3(float A0, float A1, float A2, float B) {
    uint32_t bb = marie_pun_float2u32(B);
    uint32_t diff = (marie_pun_float2u32(A0) ^ bb) |
                    (marie_pun_float2u32(A1) ^ bb) |
                    (marie_pun_float2u32(A2) ^ bb);
    return A0 == 0 || A1 == 0 || A2 == 0 || (diff & 0x80000000u) == 0;
}

float marie_surface(vec2 vi, vec2 vj, vec2 u) {
    return u.x * (vi.y - vj.y) + u.y * (vj.x - vi.x) + (vi.x * vj.y - vj.x * vi.y);
}

typedef vec4 MarieVertAttr;

typedef struct {
    vec2 pos;
    MarieVertAttr attr;
} MariePlaneVertAttr;

typedef struct {
    vec2 v0;
    vec2 v1;
    vec2 v2;
} MarieTriangle;

MarieTriangle MarieTriangle_mat3x2_mul_pos(MarieTriangle self, mat3x2 trop) {
    return (MarieTriangle){
        .v0 = mat3x2_mul_vec3(trop, vec2_and_one(self.v0)),
        .v1 = mat3x2_mul_vec3(trop, vec2_and_one(self.v1)),
        .v2 = mat3x2_mul_vec3(trop, vec2_and_one(self.v2))};
}

#include "../../../gen/l1/eve/marie/VecMarieTriangle.h"

typedef struct {
    MariePlaneVertAttr v0;
    MariePlaneVertAttr v1;
    MariePlaneVertAttr v2;
} MarieTriangleAttr;

MarieTriangleAttr MarieTriangle_goto_nat_cords_pres_par(MarieTriangle self, mat3x2 trop) {
    return (MarieTriangleAttr){
        {mat3x2_mul_vec3(trop, vec2_and_one(self.v0)), {self.v0.x, self.v0.y, 0, 0}},
        {mat3x2_mul_vec3(trop, vec2_and_one(self.v1)), {self.v1.x, self.v1.y, 0, 0}},
        {mat3x2_mul_vec3(trop, vec2_and_one(self.v2)), {self.v2.x, self.v2.y, 0, 0}},
    };
}

#include "../../../gen/l1/eve/marie/VecMarieTriangleAttr.h"

vec2 marie_intersect_lines(vec2 A1, vec2 B1, vec2 A2, vec2 B2) {
    vec2 alpha = vec2_minus_vec2(B1, A1);
    vec2 beta = vec2_minus_vec2(A2, B2);
    vec2 gamma = vec2_minus_vec2(A2, A1);
    float det_alpha_beta = alpha.x * beta.y - alpha.y * beta.x;
    float det_gamma_beta = gamma.x * beta.y - gamma.y * beta.x;
    float t1 = det_gamma_beta / det_alpha_beta;
    return vec2_add_vec2(A1, vec2_mul_scal(alpha, t1));
}

float marie_clamp_float(float a, float l, float r) {
    return (a < l) ? l : ((a <= r) ? a : r);
}

#endif
