/* solver.c */

#include "computorv1.h"

static int count_decimal_places(double num)
{
    // handle negative numbers
    num = ft_fabs(num);

    // isolate the fractional part
    double int_part;
    double frac_part = ft_modf(num, &int_part);

    // if there is no fractional part, return 0
    if (frac_part == 0.0)
    {
        return 0;
    }

    // count the number of decimal places
    int count = 0;
    const int max_decimals = 15; // prevent infinite loops for irrational numbers
    while (count < max_decimals)
    {
        double dummy_frac_part = ft_modf(frac_part, NULL);
        if (dummy_frac_part == 0.0)
        {
            break;
        }
        frac_part *= 10;
        count++;
    }

    return count;
}

// find GCD of two integers (Euclidean algorithm)
static int gcd_int(int a, int b)
{
    while (b != 0)
    {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

// find GCD of two doubles
static int find_gcd(double numerator, double denominator)
{
    // count decimal places for both numbers (eg. 2.5 -> 1 , and 1.12345 -> 5)
    int num_decimals = count_decimal_places(numerator);
    int den_decimals = count_decimal_places(denominator);

    // use the maximum precision (eg. 5)
    int max_decimals = ft_greater(num_decimals, den_decimals);

    // scale the numbers to integers (eg. 2.5*100000=250000 and 1.12345*100000=112345)
    // using ft_round because floating-point multiplication can introduce tiny precision errors
    // (e.g., 0.3 * 10 = 2.9999999999999996 instead of 3.0).
    // rounding ensures these errors are corrected before converting to integers.
    double scale = ft_pow(10, max_decimals);
    int num_scaled = (int)ft_round(numerator * scale);
    int den_scaled = (int)ft_round(denominator * scale);

    // compute GCD of the scaled integers
    return gcd_int(abs(num_scaled), ft_abs(den_scaled));
}

/*
    e_delta_sign delta_sign;              // DELTA_PLUS or DELTA_MINUS or DELTA_ZERO
    double       delta_absolute;          // |Δ| == |b² - 4ac|
    int          first_term_gcd;          // gcd(b, 2a)
    int          first_term_numerator;    // -b / gcd
    int          first_term_denominator;  // 2a / gcd
    double       first_term;              // double (-b / 2a)
    int          second_term_gcd;         // gcd(√|Δ|, 2a)
    int          second_term_numerator;   // √|Δ| / gcd
    int          second_term_denominator; // 2a / gcd
    double       second_term;             // double (√|Δ| / 2a)
    double       solution1;               // first_term + second_term
    double       solution2;               // first_term - second_term
 */

void solve(const double *polynom, s_solution *solution)
{
    double delta;
    double a;
    double b;
    double c;

    a = polynom[2];
    b = polynom[1];
    c = polynom[0];
    delta = b * b - 4 * a * c;
    solution->delta_sign = ft_sign_f(delta);
    solution->delta_absolute = ft_fabs(delta);
    solution->first_term_gcd = find_gcd(b, 2 * a);
    solution->first_term_numerator = -b / solution->first_term_gcd;
    solution->first_term_denominator = 2 * a / solution->first_term_gcd;
    solution->first_term = -b / (2 * a);
    // solution->second_term_gcd = ;
    // solution->second_term_numerator = ;
    // solution->second_term_denominator = ;
    // solution->second_term = ;
    // solution->solution1 = solution->first_term;
    // if (solution->delta_sign == DELTA_ZERO)
    // {
    //     solution->solution2 = ;
    // }
    // else
    // {
    //     solution->solution2 = 0.0;
    // }
}
