#include "ml_predict.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <math.h>
#include "../src/quaternion/ref/generic/include/intbig.h"
#include "../src/quaternion/ref/generic/include/quaternion.h"

// 下述是macOS为获取时间戳的操作
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

// ==================== 辅助函数 ====================

// 将 ibz_t 转为 long
static long ibz_to_long_safe(const ibz_t *x) {
    // 注意：仅用于调试，不要在生产环境中用 long 表示大数
    return (long) mpz_get_si(*x);
}

// 计算理想的“迹”值（trace）
// 我们使用生成元近似：trace ≈ 2 * a，其中 a 是 quat 元素实部
int quat_ideal_trace(const quat_left_ideal_t *I) {
    if (I == NULL) return 0;
    // 理想中存储的 lattice.basis[0] 通常包含 generator 信息
    // 取其第一个坐标近似为实部 a
    ibz_t a;
    ibz_init(&a);
    ibz_copy(&a, &I->lattice.basis[0][0]);
    long val = ibz_to_long_safe(&a);
    ibz_finalize(&a);
    return (int)(2 * val);
}

// 改进的机器学习预测函数，基于更复杂的启发式模型
double ml_predict_success(long norm_val, int trace_val, int kernel_order) {
    // 使用更细致的概率模型
    double score = 0.0;
    
    // 对范数进行对数缩放并评估
    double log_norm = (norm_val > 0) ? log10((double)norm_val + 1) : 0;
    if (log_norm < 12) {
        score += 0.5;  // 范数较小的理想更容易处理
    } else if (log_norm < 15) {
        score += 0.3;
    } else if (log_norm < 18) {
        score += 0.1;
    }
    
    // 对迹值进行评估
    int abs_trace = abs(trace_val);
    if (abs_trace < 100000000) {
        score += 0.3;  // 迹值较小时更优
    } else if (abs_trace < 300000000) {
        score += 0.15;
    }
    
    // 对核阶数进行评估
    if (kernel_order == 2) {
        score += 0.2;  // 优先选择核阶数为2的理想
    }
    
    // 基于组合特征的调整
    if (log_norm < 12 && abs_trace < 100000000) {
        score += 0.2;  // 范数和迹都很小的情况给予额外加分
    }
    
    // 限制分数范围
    if (score > 1.0) score = 1.0;
    
    // 转换为成功概率（非线性映射）
    double probability = score * score; // 平方放大差异
    
    return probability;
}

// 日志函数：记录一次理想尝试
// 记录到 CSV 文件，包含时间戳
void ml_log_ideal_attempt(int attempt,
                          const quat_left_ideal_t *lideal_com,
                          int kernel_order,
                          int success_flag)
{
    const char *dir_path = "./dataset";
    struct stat st = {0};

    if (stat(dir_path, &st) == -1) {
        mkdir(dir_path, 0755);
    }

    // 使用固定文件名，避免频繁创建文件
    char csv_path[512];
    snprintf(csv_path, sizeof(csv_path), "%s/ideal_data.csv", dir_path);

    // 使用追加模式，避免覆盖
    FILE *logfile = fopen(csv_path, "a+");
    if (!logfile) {
        perror("无法打开 ideal_data CSV 文件");
        return;
    }

    // 如果是第一次写入，添加表头
    if (ftell(logfile) == 0) {
        fprintf(logfile, "Timestamp,Attempt,Norm,Trace,KernelOrder,Prob,Success\n");
    }

    // 提取特征和记录
    long norm_val = ibz_to_long_safe(&lideal_com->norm);
    int trace_val = quat_ideal_trace(lideal_com);
    double prob = ml_predict_success(norm_val, trace_val, kernel_order);

    time_t t = time(NULL);
    struct tm tm_info;
    localtime_r(&t, &tm_info);
    char time_str[32];
    strftime(time_str, sizeof(time_str), "%Y-%m-%d-%H-%M-%S", &tm_info);

    fprintf(logfile, "%s,%d,%ld,%d,%d,%.3f,%d\n",
            time_str, attempt, norm_val, trace_val, kernel_order, prob, success_flag);

    fclose(logfile);
}