#include "pareto.h"
#include <cmath>
#include "utils/bidding_functions.h"
#include <fstream>
#include "smooth_sequence.h"


double deterministic_ratio(double R) {
    return 1 + 2/(R - 2 + sqrt(R * (R - 4)));
}

Plot deterministic_pareto(double R_end, double R_step) {
    Plot plot;
    for (double Re = 0; Re <= R_end; Re = Re + R_step) {
        double R = 4 * std::exp(Re);
        double c = deterministic_ratio(R);
        plot.add({R,c});
    }
    return plot;
}


void uniform_separated_parameters(double C) {
    auto h = [C](double z) {
        double a = z * C / (z * C - exp(z) + 1);
        if (a > 0) {
            return - z + log(a);
        } else {
            return 100000.;
        }
        
    };
    auto r = [C,h](vector<double> a) {
        double z = a[0];
        return exp(h(z)) * C;
    };
    vector<double> p = {0};
    vector<double> u = {0};
    double ell = ternary_search(r, p, u, 0, 0, 100);
    std::cout << "l=" << ell 
              << " h=" << h(ell) 
              << " R=" << r({ell}) << endl;
}

double uniform_separated_ratio(double C) {
    auto h = [C](double z) {
        double a = z * C / (z * C - exp(z) + 1);
        if (a > 0) {
            return - z + log(a);
        } else {
            return 100000.;
        }
        
    };
    auto r = [C,h](vector<double> a) {
        double z = a[0];
        return exp(h(z)) * C;
    };
    vector<double> p = {0};
    vector<double> u = {0};
    double ell = ternary_search(r, p, u, 0, 0, 100);
    std::cout << ell << " " << r({ell});
    return r({ell});
}

Plot uniform_separated_pareto(double C_step) {
    Plot plot;
    for (double Ce = C_step; Ce <= 1; Ce = Ce + C_step) {
        double C = exp(Ce);
        double R = uniform_separated_ratio(C);
        plot.add({R,C});
    }
    return plot;
}

Plot stochastic_lower_bound(double R_end, double R_step) {
    double c;
    Plot plot;
    for (double R = exp(1); R <= R_end; R = R + R_step) {
        c = 1 + 1/(R * log(R * (log(R) + log(log(R)))));
        plot.add({R,c});
    }
    return plot;
}

Plot contiguous_pareto(double R_end, double R_step) {
    double c;
    Plot plot;
    for (double R = exp(1); R <= R_end; R = R + R_step) {
        c = contiguous_ratio(R);
        plot.add({R,c});
    }
    return plot;
}


std::pair<std::vector<double>,double> separated_consistency(double const R, int n, int iter, double precision, double iter_precision, double ternary_precision) {
    vector<pair<double, double>> ranges = {
        {1    , 5}, 
        {precision, 5  },  
    };
    for (int i = 0; i < n; i++) {
        ranges.push_back({precision, 5});
    }
    auto f = tight_separated_sequence_functional(R, precision);
    vector<double> params = multidimensional_ternary_search(
        f,
        ranges,
        iter,
        iter_precision,
        ternary_precision
    );
    return make_pair(params, f(params));
}

void write_separated_pareto(double R_start, double R_end, double R_step, int n, int iter, double precision, double iter_precision, double ternary_precision) {
    string filename = "../outputs/separated_pareto_" + std::to_string(n) + ".txt";
    double R;
    ofstream outFile(filename);
    if (!outFile) {
        std::cerr << "Le fichier n'est pas ouvert\n";
    }
    for (double R_e = R_start; R_e < R_end; R_e = R_e + R_step) {
        R = exp(R_e);
        auto [params,C] = separated_consistency(R,n,iter,precision, iter_precision, ternary_precision);
        outFile << R << " " << C << " ";
        for (int i = 0; i < n+2; i++) {
            outFile << params[i] << " ";
        }
        outFile << "\n";
        std::cout << R << " " << C << "\n";
    }
    outFile.close();
}
