#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);
}

// 简单启发式预测函数（可替换为导入的 ML 模型）
// double ml_predict_success(long norm_val, int trace_val, int kernel_order) {
//     // 放宽条件，收集更多数据
//     double score = 0.0;
//     score += (norm_val < 50) ? 0.3 : 0.1;        // 放宽norm条件
//     score += (abs(trace_val) < 20) ? 0.3 : 0.1;  // 放宽trace条件  
//     score += (kernel_order > 20) ? 0.2 : 0.1;    // 放宽kernel条件

//     // 降低阈值
//     if (score > 0.6) return 0.7;
//     else if (score > 0.4) return 0.5;
//     else return 0.3;  // 即使概率低也尝试
// }

// ML测试部分第二版本
double ml_predict_success(long norm_val, int trace_val, int kernel_order) {
    // 简单严格的版本
    double score = 0.0;
    
    // 严格的条件
    score += (norm_val < 1000000000000000000) ? 0.4 : 0.0;        // norm必须小于1e18
    score += (abs(trace_val) < 500000000) ? 0.4 : 0.0;            // trace绝对值必须小于5e8
    score += (kernel_order == 2) ? 0.2 : 0.0;                     // kernel必须等于2

    // 严格的阈值
    if (score > 0.9) return 0.9;     // 完美匹配所有条件
    else if (score > 0.5) return 0.6; // 匹配大部分条件
    else return 0.1;                  // 不匹配
}

// 日志函数：记录一次理想尝试
// 以下是第一代版本
// void ml_log_ideal_attempt(int attempt, const quat_left_ideal_t *lideal_com, int kernel_order, int success_flag) {
//     FILE *logfile = fopen("ideal_data.csv", "a");
//     if (!logfile) return;

//     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);

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


// 第二代版本日志函数：记录一次理想尝试
// 记录到 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 = "/root/cryptologic_competition_a1_6/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);

    // 控制台输出成功案例
    if (success_flag) {
        printf("[SUCCESS] attempt=%d norm=%ld trace=%d kernel=%d\n",
               attempt, norm_val, trace_val, kernel_order);
    } else {
        printf("[SKIP] attempt=%d norm=%ld trace=%d kernel=%d prob=%.3f\n",
               attempt, norm_val, trace_val, kernel_order, prob);
    }
}