/* Copyright (c) KylinSoft  Co., Ltd. [2023].All rights reserved.
    [ostree-maintain-daemon] licensed under the [Your LICENSE].
    Author: [ZhangTingting]
    Create: [2024]
*/

#include <ostree-1/ostree.h>
#include "mm-public.h"

uintmax_t etc_size = 0;
uintmax_t usr_size = 0;
uintmax_t var_size = 0;
uintmax_t total_size = 0;

gchar *get_pending_deploy_hash()
{
    g_autoptr(GError) error = NULL;
    OstreeDeployment *pending_deployment = NULL;
    g_autoptr(OstreeSysroot) sysroot = NULL;

    /* 创建并初始化 sysroot 对象 */
    sysroot = ostree_sysroot_new(NULL);
    if (!sysroot || !ostree_sysroot_initialize(sysroot, &error)) {
        g_clear_object(&sysroot);  // 显式清除并置NULL
        g_error("mm: Failed to initialize sysroot: %s", error ? error->message : "unknown error");
        return NULL;
    }

    if (!ostree_sysroot_load(sysroot, NULL, &error)) {
        g_error("mm: Failed to load sysroot: %s", error->message);
        return NULL;
    }

    // 查找 pending 状态的部署
    OstreeDeployment *boot_deployment = ostree_sysroot_get_booted_deployment(sysroot);
    g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments(sysroot);
    
    if (!deployments || deployments->len == 0) {
        g_info("mm: No deployments found.");
        return NULL;
    }

    OstreeDeployment *deployment = (OstreeDeployment*)g_ptr_array_index(deployments, 0);
    if (boot_deployment && deployment && !ostree_deployment_equal(deployment, boot_deployment)) 
    {
        pending_deployment = deployment;
    }

    if (pending_deployment == NULL) {
        g_info("mm: No pending deployment found.");
        return NULL;
    }

    gchar *hash_value = g_malloc0(BUFFER_SIZE * sizeof(char));
    if (hash_value == NULL) {
        return NULL;
    }

    g_sprintf(hash_value, "%s.%d", 
              ostree_deployment_get_csum(pending_deployment), 
              ostree_deployment_get_deployserial(pending_deployment));
    return hash_value;
}

gchar *get_current_deploy_hash()
{
    g_autoptr(GError) error = NULL;
    g_autoptr(OstreeSysroot) sysroot = NULL;

    /* 创建并初始化 sysroot 对象 */
    sysroot = ostree_sysroot_new_default();
    if (!sysroot || !ostree_sysroot_initialize(sysroot, &error)) {
        g_clear_object(&sysroot);  // 显式清除并置NULL
        g_error("mm: Failed to initialize sysroot: %s", error ? error->message : "unknown error");
        return NULL;
    }

    /* 加载 sysroot 数据 */
    if (!ostree_sysroot_load(sysroot, NULL, &error)) {
        g_error("mm: Failed to load sysroot: %s", error->message);
        return NULL;
    }
    
    OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment(sysroot);
    if (!booted_deployment)
    {
        g_info("mm: No booted deployment found.");
        return NULL;
    }

    gchar *hash_value = g_malloc0(BUFFER_SIZE * sizeof(char));
    if (hash_value == NULL) {
        g_info("mm: Memory allocation failed");
        return NULL;
    }
    
    g_sprintf(hash_value, "%s.%d", 
              ostree_deployment_get_csum(booted_deployment), 
              ostree_deployment_get_deployserial(booted_deployment));
    return hash_value;
}

// 获取ovl目录路径
void append_char_to_string(gchar *str, gchar ch)
{
    if (str == NULL) 
    {
        return;
    }
    size_t len = strlen(str);
    str[len] = ch;
    str[len + 1] = '\0';
}
char *mm_get_ovl_dir_path()
{
    char buffer[BUFFER_SIZE];
    char *hash_buf = calloc(BUFFER_SIZE,sizeof(char));
    gchar *booted_hash = get_current_deploy_hash();
    g_snprintf(hash_buf, BUFFER_SIZE, "%s%s", "/ostree/pkgs/ovl-", booted_hash);
    g_free(booted_hash);
    return hash_buf;
}

/*计算待处理目录大小*/
// Helper function to convert size to human-readable format
char *print_human_readable_size(uintmax_t size)
{
    char *space_size = calloc(1024, sizeof(char));
    const char *suffixes[] = {"B", "KB", "MB", "GB", "TB"};
    int suffix_index = 0;
    double readable_size = size;

    while (readable_size >= 1024 && suffix_index < (sizeof(suffixes) / sizeof(suffixes[0]))) {
        readable_size /= 1024;
        suffix_index++;
    }

    // printf("%.2f%s\n", readable_size, suffixes[suffix_index]);
    sprintf(space_size, "%.2f%s", readable_size, suffixes[suffix_index]);
    g_info("mm: The size of the data to be processed is [%s].", space_size);
    return space_size;
}

// Recursive function to calculate disk usage
uintmax_t calculate_disk_usage(const char *path)
{
    DIR *dir;
    struct dirent *entry;
    struct stat statbuf;
    char filepath[1024];
    uintmax_t total = 0;

    if ((dir = opendir(path)) == NULL) {
        /// perror("opendir");
        return 0;
    }

    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);

        if (lstat(filepath, &statbuf) == -1) {
            perror("lstat");
            closedir(dir);
            return 0;
        }

        if (S_ISDIR(statbuf.st_mode)) {
            total += calculate_disk_usage(filepath);
        } else {
            total += statbuf.st_size;
        }
    }

    closedir(dir);
    return total;
}

