#include "zvfs_open_file.h"
#include "zvfs_inode.h"
#include "zvfs.h"

#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

/* ------------------------------------------------------------------ */
/* alloc / free                                                         */
/* ------------------------------------------------------------------ */

struct zvfs_open_file *openfile_alloc(int fd,
               struct zvfs_inode       *inode,
               int                      flags,
               uint64_t                 handle_id)
{
    struct zvfs_open_file *of = calloc(1, sizeof(*of));
    if (!of)
        return NULL;

    of->fd        = fd;
    of->inode     = inode;
    of->handle_id = handle_id;
    of->flags     = flags;
    of->fd_flags  = 0;
    of->offset    = 0;

    return of;
}

void openfile_free(struct zvfs_open_file *of)
{
    free(of);
}

/* ------------------------------------------------------------------ */
/* hash table operations  （调用方持有 g_fs.fd_mu）                    */
/* ------------------------------------------------------------------ */

void openfile_insert(struct zvfs_open_file *of)
{
    HASH_ADD_INT(g_fs.fd_table, fd, of);
}

struct zvfs_open_file *openfile_lookup(int fd)
{
    struct zvfs_open_file *of = NULL;
    HASH_FIND_INT(g_fs.fd_table, &fd, of);
    return of;
}

void openfile_remove(int fd)
{
    struct zvfs_open_file *of = openfile_lookup(fd);
    if (of)
        HASH_DEL(g_fs.fd_table, of);
}

/* ------------------------------------------------------------------ */
/* lseek  （调用方持有 of->inode->mu）                                  */
/* ------------------------------------------------------------------ */

uint64_t openfile_seek(struct zvfs_open_file *of, int64_t offset, int whence)
{
    int64_t new_off;

    switch (whence) {
    case SEEK_SET:
        new_off = offset;
        break;

    case SEEK_CUR:
        new_off = (int64_t)of->offset + offset;
        break;

    case SEEK_END:
        /* logical_size 由调用方在持锁状态下保证可见 */
        new_off = (int64_t)of->inode->logical_size + offset;
        break;

    default:
        errno = EINVAL;
        return (uint64_t)-1;
    }

    if (new_off < 0) {
        errno = EINVAL;
        return (uint64_t)-1;
    }

    of->offset = (uint64_t)new_off;
    return of->offset;
}
