
#include "common/config.h"
#include "proto/ipc_proto.h"
#include "ipc_reactor.h"
#include "ipc_cq.h"
#include "spdk_engine_wrapper.h"

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>

// #define IPC_REACTOR_ECHO

#define IPC_REACTOR_ZVFS

extern struct zvfs_spdk_io_engine g_engine;


#ifdef IPC_REACTOR_ECHO
static void on_accept(struct zvfs_conn *conn, void *ctx)
{
    printf("client connected fd=%d\n",
           zvfs_conn_get_fd(conn));
}


static void on_read(struct zvfs_conn *c, void *ctx)
{
    int fd = zvfs_conn_get_fd(c);

    char buf[4096];

    ssize_t n = read(fd, buf, sizeof(buf));

    if (n == 0) {
        zvfs_conn_close(c);
        return;
    }

    if (n < 0) {

        if (errno == EAGAIN || errno == EWOULDBLOCK)
            return;

        perror("read");
        zvfs_conn_close(c);
        return;
    }

    printf("recv %ld bytes: %.*s\n", n, (int)n, buf);

    ssize_t w = write(fd, buf, n);

    if (w < 0) {
        perror("write");
        zvfs_conn_close(c);
        return;
    }
}


static void on_write(struct zvfs_conn *conn, void *ctx)
{
    /* echo server 不需要 write queue */
}


static void on_close(struct zvfs_conn *conn, void *ctx)
{
    printf("connection closed fd=%d\n",
           zvfs_conn_get_fd(conn));
}


int main()
{
    struct zvfs_reactor_opts opts = {
        .socket_path = "/tmp/zvfs.sock",
        .backlog = 128,
        .max_events = 64,
        .on_accept = on_accept,
        .on_read = on_read,
        .on_write = on_write,
        .on_close = on_close,
        .cb_ctx = NULL
    };

    struct zvfs_reactor *r = zvfs_reactor_create(&opts);

    printf("echo server started: %s\n", opts.socket_path);

    zvfs_reactor_run(r);

    return 0;
}


#else
static void on_accept(struct zvfs_conn *conn, void *ctx)
{
    struct {
        uint8_t *buf;
        size_t   len;
        size_t   cap;
    } *rctx = calloc(1, sizeof(*rctx));

    if (!rctx) {
        fprintf(stderr, "[accept] alloc conn ctx failed\n");
        zvfs_conn_close(conn);
        return;
    }

    rctx->cap = ZVFS_IPC_BUF_SIZE;
    rctx->buf = calloc(1, rctx->cap);
    if (!rctx->buf) {
        fprintf(stderr, "[accept] alloc conn rx buffer failed\n");
        free(rctx);
        zvfs_conn_close(conn);
        return;
    }
    zvfs_conn_set_ctx(conn, rctx);

    printf("client connected fd=%d\n",
           zvfs_conn_get_fd(conn));
}

static void on_read(struct zvfs_conn *c, void *ctx)
{
    int fd = zvfs_conn_get_fd(c);
    struct {
        uint8_t *buf;
        size_t   len;
        size_t   cap;
    } *rctx = zvfs_conn_get_ctx(c);

    if (!rctx || !rctx->buf || rctx->cap == 0) {
        fprintf(stderr, "[read] invalid conn ctx fd=%d\n", fd);
        zvfs_conn_close(c);
        return;
    }

    for (;;) {
        if (rctx->len >= rctx->cap) {
            fprintf(stderr, "[read] rx buffer overflow fd=%d len=%zu cap=%zu\n",
                    fd, rctx->len, rctx->cap);
            zvfs_conn_close(c);
            return;
        }

        ssize_t n = read(fd, rctx->buf + rctx->len, rctx->cap - rctx->len);
        if (n == 0) {
            fprintf(stderr, "[read] fd=%d closed\n", fd);
            zvfs_conn_close(c);
            return;
        }

        if (n < 0) {
            if (errno != EAGAIN && errno != EWOULDBLOCK) {
                perror("[read]");
                zvfs_conn_close(c);
                return;
            }
            break;
        }

        rctx->len += (size_t)n;
    }

    size_t offset = 0;
    while (offset < rctx->len) {
        struct zvfs_req *req = calloc(1, sizeof(*req));
        if (!req) {
            fprintf(stderr, "malloc failed\n");
            break;
        }

        size_t consumed = zvfs_deserialize_req(rctx->buf + offset, rctx->len - offset, req);
        if (consumed == 0) {
            free(req);
            break; /* 等待更多数据 */
        }

        printf("[req][%s]\n", cast_opcode2string(req->opcode));
        req->conn = c;
        offset += consumed;

        if (dispatch_to_worker(req) < 0) {
            fprintf(stderr, "[dispatcher] [fd:%d] dispatch error\n", c->fd);
        }
    }

    if (offset > 0) {
        size_t remain = rctx->len - offset;
        if (remain > 0) {
            memmove(rctx->buf, rctx->buf + offset, remain);
        }
        rctx->len = remain;
    }

    if (rctx->len == rctx->cap) {
        fprintf(stderr, "[read] request too large or malformed fd=%d cap=%zu\n",
                fd, rctx->cap);
        zvfs_conn_close(c);
    }
}

static void on_close(struct zvfs_conn *conn, void *ctx)
{
    struct {
        uint8_t *buf;
        size_t   len;
        size_t   cap;
    } *rctx = zvfs_conn_get_ctx(conn);

    if (rctx) {
        free(rctx->buf);
        free(rctx);
        zvfs_conn_set_ctx(conn, NULL);
    }

    printf("connection closed fd=%d\n",
           zvfs_conn_get_fd(conn));
}


int main(void){


    const char *bdev_name = getenv("SPDK_BDEV_NAME") ? getenv("SPDK_BDEV_NAME") : ZVFS_BDEV;
    const char *json_file = getenv("SPDK_JSON_CONFIG") ? getenv("SPDK_JSON_CONFIG") : SPDK_JSON_PATH;

    g_cq = CQ_Create();
    
    zvfs_engine_init(bdev_name, json_file, 4);
    
    struct zvfs_reactor_opts opts = {
        .socket_path = ZVFS_IPC_DEFAULT_SOCKET_PATH,
        .backlog = 128,
        .max_events = 64,
        .on_accept = on_accept,
        .on_read = on_read,
        .on_write = NULL,
        .on_close = on_close,
        .cb_ctx = &g_engine
    };

    struct zvfs_reactor *r = zvfs_reactor_create(&opts);
    zvfs_reactor_run(r);



    if(g_cq) CQ_Destroy(g_cq);
}
#endif
