#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "zvfs_hook_dir.h"
#include "zvfs_hook_init.h"
#include "zvfs_hook_reentrant.h"
#include "fs/zvfs.h"
#include "fs/zvfs_inode.h"
#include "fs/zvfs_path_entry.h"

/* SPDK io engine - blob_delete 声明 */
#include "../spdk_engine/io_engine.h"

#include <errno.h>
#include <string.h>
#include <limits.h>
#include <linux/fs.h>       /* RENAME_EXCHANGE, RENAME_NOREPLACE */

/* ------------------------------------------------------------------ */
/* 内部：执行 unlink 的 zvfs 侧清理                                     */
/* ------------------------------------------------------------------ */

/*
 * zvfs_unlink_path - 对一个确认属于 zvfs 的绝对路径执行清理。
 *
 * 调用时机：real_unlink* 已成功返回之后。
 *
 * 逻辑：
 *   1. 持 path_mu 查 path_cache
 *   2. 找到 → 持 inode_mu 查 inode
 *   3. 持 inode->mu 检查 ref_count
 *      - ref_count == 0：直接 blob_delete，inode_remove，inode_free，path_cache_remove
 *      - ref_count  > 0：标记 deleted = true，path_cache_remove
 *        （inode 和 blob 的清理推迟到 close 路径中 ref_count 归零时）
 */
static void
zvfs_unlink_path(const char *abspath)
{
    /* --- 查 path_cache -------------------------------------------- */
    pthread_mutex_lock(&g_fs.path_mu);
    struct zvfs_path_entry *pe = path_cache_lookup(abspath);
    if (!pe) {
        /*
         * 不在缓存里：该文件可能从未被 open 过（没有 inode 对象）。
         * 无内存状态需要清理，直接返回。
         * blob 也不存在（文件从未被 zvfs open 创建），所以安全。
         */
        pthread_mutex_unlock(&g_fs.path_mu);
        return;
    }
    struct zvfs_inode *inode = pe->inode;
    pthread_mutex_unlock(&g_fs.path_mu);

    /* --- 持 inode->mu 决策 ---------------------------------------- */
    pthread_mutex_lock(&inode->mu);
    int ref = atomic_load(&inode->ref_count);

    if (ref == 0) {
        /*
         * 没有 fd 打开：立即清理。
         * 顺序：blob_delete → inode_remove（出全局表）→ path_cache_remove
         *       → inode_free（释放内存）
         */
        pthread_mutex_unlock(&inode->mu);

        blob_delete(inode->blob_id);

        pthread_mutex_lock(&g_fs.inode_mu);
        inode_remove(inode->blob_id);
        pthread_mutex_unlock(&g_fs.inode_mu);

        pthread_mutex_lock(&g_fs.path_mu);
        path_cache_remove(abspath);
        pthread_mutex_unlock(&g_fs.path_mu);

        inode_free(inode);

    } else {
        /*
         * 还有 fd 打开：Unix 延迟删除语义。
         * 标记 deleted，让 close 路径在 ref_count 归零时负责 blob_delete。
         * 同时把 path 从缓存里摘掉（路径已从目录树消失）。
         */
        inode->deleted = true;
        pthread_mutex_unlock(&inode->mu);

        pthread_mutex_lock(&g_fs.path_mu);
        path_cache_remove(abspath);
        pthread_mutex_unlock(&g_fs.path_mu);
    }
}

/* ------------------------------------------------------------------ */
/* unlink                                                               */
/* ------------------------------------------------------------------ */

int
unlink(const char *path)
{
    ZVFS_HOOK_ENTER();
    int ret;

    if (ZVFS_IN_HOOK() || !zvfs_is_zvfs_path(path)) {
        ret = real_unlink(path);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    zvfs_ensure_init();

    /* 先让真实 FS 删除文件（xattr 随之消失） */
    ret = real_unlink(path);
    if (ret == 0)
        zvfs_unlink_path(path);

    ZVFS_HOOK_LEAVE();
    return ret;
}

/* ------------------------------------------------------------------ */
/* unlinkat                                                             */
/* ------------------------------------------------------------------ */

int
unlinkat(int dirfd, const char *path, int flags)
{
    ZVFS_HOOK_ENTER();
    int ret;

    /*
     * AT_REMOVEDIR：rmdir 语义，目录由真实 FS 管理，直接透传。
     */
    if (flags & AT_REMOVEDIR) {
        ret = real_unlinkat(dirfd, path, flags);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    /* 解析绝对路径，判断是否属于 zvfs */
    char abspath[PATH_MAX];
    if (zvfs_resolve_atpath(dirfd, path, abspath, sizeof(abspath)) < 0) {
        ZVFS_HOOK_LEAVE();
        return -1;   /* errno already set */
    }

    if (ZVFS_IN_HOOK() || !zvfs_is_zvfs_path(abspath)) {
        ret = real_unlinkat(dirfd, path, flags);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    zvfs_ensure_init();

    ret = real_unlinkat(dirfd, path, flags);
    if (ret == 0)
        zvfs_unlink_path(abspath);

    ZVFS_HOOK_LEAVE();
    return ret;
}

/* ------------------------------------------------------------------ */
/* 内部：执行 rename 的 zvfs 侧缓存更新                                 */
/* ------------------------------------------------------------------ */

/*
 * zvfs_rename_paths - 在 real_rename* 成功后更新 path_cache。
 *
 * 如果 newpath 原本也在缓存里（覆盖式 rename），其 inode 需要先做
 * unlink 清理（与 zvfs_unlink_path 逻辑相同）。
 */
static void
zvfs_rename_paths(const char *oldabs, const char *newabs)
{
    /* 处理 newpath 被覆盖的情况 */
    pthread_mutex_lock(&g_fs.path_mu);
    struct zvfs_path_entry *victim = path_cache_lookup(newabs);
    pthread_mutex_unlock(&g_fs.path_mu);

    if (victim) {
        /*
         * newpath 是 zvfs 文件且已经在缓存里：
         * real_rename 已经把它从磁盘上删掉了，
         * 走和 unlink 一样的延迟/立即 blob_delete 逻辑。
         */
        zvfs_unlink_path(newabs);
    }

    /* 把 oldpath 的缓存条目 rename 到 newpath */
    pthread_mutex_lock(&g_fs.path_mu);
    path_cache_rename(oldabs, newabs);
    pthread_mutex_unlock(&g_fs.path_mu);
}

/* ------------------------------------------------------------------ */
/* rename                                                               */
/* ------------------------------------------------------------------ */

int
rename(const char *oldpath, const char *newpath)
{
    ZVFS_HOOK_ENTER();
    int ret;

    int old_is_zvfs = zvfs_is_zvfs_path(oldpath);
    int new_is_zvfs = zvfs_is_zvfs_path(newpath);

    if (ZVFS_IN_HOOK() || (!old_is_zvfs && !new_is_zvfs)) {
        ret = real_rename(oldpath, newpath);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    /*
     * 跨域 rename（一个在 /zvfs 一个不在）：不支持，返回 EXDEV。
     * 和跨文件系统 rename 的语义一致。
     */
    if (old_is_zvfs != new_is_zvfs) {
        errno = EXDEV;
        ZVFS_HOOK_LEAVE();
        return -1;
    }

    zvfs_ensure_init();

    ret = real_rename(oldpath, newpath);
    if (ret == 0)
        zvfs_rename_paths(oldpath, newpath);

    ZVFS_HOOK_LEAVE();
    return ret;
}

/* ------------------------------------------------------------------ */
/* renameat                                                             */
/* ------------------------------------------------------------------ */

int
renameat(int olddirfd, const char *oldpath,
         int newdirfd, const char *newpath)
{
    ZVFS_HOOK_ENTER();
    int ret;

    char oldabs[PATH_MAX], newabs[PATH_MAX];

    if (zvfs_resolve_atpath(olddirfd, oldpath, oldabs, sizeof(oldabs)) < 0 ||
        zvfs_resolve_atpath(newdirfd, newpath, newabs, sizeof(newabs)) < 0) {
        ZVFS_HOOK_LEAVE();
        return -1;
    }

    int old_is_zvfs = zvfs_is_zvfs_path(oldabs);
    int new_is_zvfs = zvfs_is_zvfs_path(newabs);

    if (ZVFS_IN_HOOK() || (!old_is_zvfs && !new_is_zvfs)) {
        ret = real_renameat(olddirfd, oldpath, newdirfd, newpath);
        ZVFS_HOOK_LEAVE();
        return ret;
    }

    if (old_is_zvfs != new_is_zvfs) {
        errno = EXDEV;
        ZVFS_HOOK_LEAVE();
        return -1;
    }

    zvfs_ensure_init();

    ret = real_renameat(olddirfd, oldpath, newdirfd, newpath);
    if (ret == 0)
        zvfs_rename_paths(oldabs, newabs);

    ZVFS_HOOK_LEAVE();
    return ret;
}
