#define _XOPEN_SOURCE 700 //strptime(ts, "%Y%m%d%H%M", &tm)用这个非标准函数，不使用这2个的话无法使用
#define _DEFAULT_SOURCE

#include "common.h"
#include "device_id_change.h"

#define BUFFER_SIZE 1024

char buffer_device_change_fail[40]; // 用于回退存储文件内容

// 判断文件是否存在
int file_exists(const char *path) {
    return access(path, F_OK) == 0;
}

// 删除文件
int remove_file(const char *path) {
    if (remove(path) == 0) {
        return 1;
    } else {
        my_zlog_warn("删除文件失败: %s", path);
        return 0;
    }
}

// 递归创建目录
int create_directory_if_not_exists(const char *path) {
    char temp[1024];
    size_t len = strlen(path);

    if (len >= sizeof(temp)) {
        my_zlog_error("路径过长: %s", path);
        return -1;
    }

    // 拷贝路径并保证以 '/' 结尾
    strncpy(temp, path, sizeof(temp));
    if (temp[len - 1] != '/') {
        temp[len] = '/';
        temp[len + 1] = '\0';
        len++;
    }

    for (size_t i = 1; i < len; i++) {
        if (temp[i] == '/') {
            temp[i] = '\0';
            if (access(temp, F_OK) != 0) {
                if (mkdir(temp, 0755) != 0) {
                    my_zlog_error("创建目录失败: %s (%s)", temp, strerror(errno));
                    return -1;
                } else {
                    my_zlog_debug("已创建目录: %s", temp);
                }
            }
            temp[i] = '/';
        }
    }

    return 0;
}

// 复制文件内容
int copy_file(const char *src, const char *dst) {
    FILE *fsrc = fopen(src, "rb");
    if (!fsrc) {
        my_zlog_warn("无法打开源文件: %s", src);
        return -1;
    }

    FILE *fdst = fopen(dst, "wb");
    if (!fdst) {
        my_zlog_warn("无法打开目标文件: %s", dst);
        fclose(fsrc);
        return -1;
    }

    char buffer[BUFFER_SIZE];
    size_t bytes;
    while ((bytes = fread(buffer, 1, BUFFER_SIZE, fsrc)) > 0) {
        if (fwrite(buffer, 1, bytes, fdst) != bytes) {
            my_zlog_warn("写入文件出错: %s", dst);
            fclose(fsrc);
            fclose(fdst);
            return -1;
        }
    }

    fclose(fsrc);
    fclose(fdst);
    return 0;
}

// 重命名并移动文件
int rename_and_move_file(const char *src, const char *new_name, const char *dst_dir) {
    char dst_path[BUFFER_SIZE];
    snprintf(dst_path, sizeof(dst_path), "%s/%s", dst_dir, new_name);

    my_zlog_debug("尝试移动文件: %s -> %s", src, dst_path);

    if (rename(src, dst_path) == 0) {
        my_zlog_debug("文件已移动至 %s", dst_path);
        return 0;
    }

    my_zlog_warn("rename()失败: %s -> %s, 错误: %s", src, dst_path, strerror(errno));

    if (errno == EXDEV) {  // 跨文件系统移动
        if (copy_file(src, dst_path) == 0) {
            if (remove(src) == 0) {
                my_zlog_debug("跨文件系统移动成功: %s", dst_path);
                return 0;
            } else {
                my_zlog_warn("删除源文件失败: %s", src);
                return -1;
            }
        } else {
            my_zlog_warn("复制文件失败: %s -> %s", src, dst_path);
            return -1;
        }
    }

    my_zlog_warn("移动文件失败: %s", strerror(errno));
    return -1;
}

// 提取文件名中的时间戳（例如 Deviceld.txt.202405100930）
time_t extract_timestamp(const char *filename) {
    char ts[20];
    const char *dot = strrchr(filename, '.');
    if (dot) {
        strncpy(ts, dot + 1, sizeof(ts) - 1);
        ts[sizeof(ts) - 1] = '\0';

        struct tm tm = {0};
        if (strptime(ts, "%Y%m%d%H%M", &tm)) {
            return mktime(&tm);
        }
    }
    return 0;
}

// 查找目录中最 
char *find_latest_file(const char *dir_path) {
    DIR *dir = opendir(dir_path);
    if (!dir) {
        my_zlog_error("无法打开目录: %s", dir_path);
        return NULL;
    }

    struct dirent *entry;
    time_t latest_time = 0;
    char *latest_file = NULL;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG) {
            time_t ts = extract_timestamp(entry->d_name);
            if (ts > latest_time) {
                latest_time = ts;
                free(latest_file);
                latest_file = strdup(entry->d_name);
            }
        }
    }

    closedir(dir);
    return latest_file;
}

// 写入设备 ID 到文件
int write_device_id(const char *path, const char *device_id) {
    FILE *f = fopen(path, "w");
    if (!f) {
        my_zlog_error("无法写入文件: %s", path);
        return -1;
    }

    fprintf(f, "%s", device_id);
    fclose(f);
    my_zlog_debug("成功写入设备ID到 %s", path);

    if(system("sudo reboot")!=0){
        my_zlog_error("reboot fail");
    }
    
    return 0;
}

// 改名并备份设备文件
int device_changename_back(const char *device_date, const char *device_id) {
    // 调试输出：源文件是否存在
    if (!file_exists(DEVICE_NAME_FILE)) {
        my_zlog_warn("设备文件不存在: %s", DEVICE_NAME_FILE);
        return 0;
    }

    my_zlog_debug("设备文件存在，准备备份");

    if (create_directory_if_not_exists(DEVICE_NAME_DIR) != 0) {
        my_zlog_error("创建备份目录失败");
        return -1;
    }

    char new_name[256];
    snprintf(new_name, sizeof(new_name), "Deviceld.txt.%s", device_date);

    my_zlog_debug("新文件名: %s", new_name);

    // 移动文件（可能失败）
    if (rename_and_move_file(DEVICE_NAME_FILE, new_name, DEVICE_NAME_DIR) != 0) {
        my_zlog_warn("设备文件备份失败");
        return -1;
    }

    return write_device_id(DEVICE_NAME_FILE, device_id);
}

// 获取最近的设备备份文件路径（回退使用）
char *device_changename_back_fail(void) {
    char *latest_file = find_latest_file(DEVICE_NAME_DIR);
    if (!latest_file) {
        my_zlog_warn("未找到任何备份文件");
        return NULL;
    }

    size_t size = strlen(DEVICE_NAME_DIR) + strlen(latest_file) + 2;
    char *full_path = malloc(size);
    if (!full_path) {
        free(latest_file);
        my_zlog_error("内存分配失败");
        return NULL;
    }

    snprintf(full_path, size, "%s/%s", DEVICE_NAME_DIR, latest_file);
    my_zlog_debug("回退路径为: %s", full_path);

    free(latest_file);

   return full_path;
}

//读取失败，读取备份内容
char *read_device_back_fail() {
    FILE *file;
    char *device_back_fail =device_changename_back_fail();
    if(device_back_fail !=NULL) { //如果在备份文件中找到
        file = fopen(device_back_fail, "r"); // 以只读模式打开文件
        if (fgets(buffer_device_change_fail, sizeof(buffer_device_change_fail), file) != NULL) {
        // 如果文件内容不为空
        fclose(file);
        my_zlog_debug("读取到备份文件内容: %s", buffer_device_change_fail);
        free(device_back_fail);
        return  buffer_device_change_fail;
        } else {
            my_zlog_debug("读取备份文件失败");
        }
        fclose(file); 
        return NULL;
    }
    return NULL;
}
