#include <gtest/gtest.h>
#include <thread>
#include <vector>
#include <fcntl.h>
extern "C" {
#include "gr_api.h"
#include "gr_errno.h"
}

#define TEST_LOG_DIR "./test_log"
#define TEST_DIR "complexdir"
#define TEST_FILE1 "complexfile1"
#define TEST_FILE2 "complexfile2"
#define ONE_GB 1024 * 1024 * 1024
#define SERVER_ADDR "127.0.0.1:19225"

int errorcode = 0;
const char *errormsg = NULL;
gr_instance_handle g_inst_handle1 = NULL;
gr_instance_handle g_inst_handle2 = NULL;
gr_instance_handle g_inst_handle3 = NULL;
gr_instance_handle g_inst_handle4 = NULL;

gr_vfs_handle g_vfs_handle1;
gr_vfs_handle g_vfs_handle2;
gr_vfs_handle g_vfs_handle3;
gr_vfs_handle g_vfs_handle4;

gr_file_handle file_handle1;
gr_file_handle file_handle2;
gr_file_handle file_handle3;
gr_file_handle file_handle4;

gr_param_t g_gr_param;

class ComplexGRApiTest : public ::testing::Test {
protected:
    void SetUp() override {
        strcpy(g_gr_param.log_home, "./testlog");
        g_gr_param.log_level = 255;
        g_gr_param.log_backup_file_count = 100;
        g_gr_param.log_max_file_size = ONE_GB;
        int result = gr_init(g_gr_param);
        ASSERT_EQ(result, GR_SUCCESS) << "Failed to initialize logger";

        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle2), GR_SUCCESS);
        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle3), GR_SUCCESS);
        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle4), GR_SUCCESS);
        gr_vfs_create(g_inst_handle1, TEST_DIR, 0);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle1, TEST_DIR, &g_vfs_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle2, TEST_DIR, &g_vfs_handle2), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle1, TEST_DIR, &g_vfs_handle3), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle2, TEST_DIR, &g_vfs_handle4), GR_SUCCESS);
        

        EXPECT_EQ(gr_file_create(g_vfs_handle1, TEST_FILE1, NULL), GR_SUCCESS);
        EXPECT_EQ(gr_file_create(g_vfs_handle2, TEST_FILE2, NULL), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle1, TEST_FILE1, O_RDWR | O_SYNC, &file_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle2, TEST_FILE2, O_RDWR | O_SYNC, &file_handle2), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle3, TEST_FILE1, O_RDWR | O_SYNC, &file_handle3), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle4, TEST_FILE2, O_RDWR | O_SYNC, &file_handle4), GR_SUCCESS);
    }
    
    void TearDown() override {
        EXPECT_EQ(gr_file_close(g_vfs_handle1, &file_handle1, true), GR_SUCCESS);
        EXPECT_EQ(gr_file_close(g_vfs_handle1, &file_handle2, true), GR_SUCCESS);
#ifndef ENABLE_WORM
        EXPECT_EQ(gr_file_delete(g_vfs_handle1, TEST_FILE1, 0), GR_SUCCESS);
        EXPECT_EQ(gr_file_delete(g_vfs_handle1, TEST_FILE2, 0), GR_SUCCESS);
#endif
        EXPECT_EQ(gr_vfs_unmount(&g_vfs_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_unmount(&g_vfs_handle2), GR_SUCCESS);
#ifndef ENABLE_WORM
        EXPECT_EQ(gr_vfs_delete(g_inst_handle1, TEST_DIR, 1), GR_SUCCESS);
#endif
    }
};

void writeData(gr_file_handle *file_handle, gr_vfs_handle vfs_handle, const char* data, size_t size, int64_t offset) {
    EXPECT_EQ(gr_file_pwrite(vfs_handle, file_handle, data, size, offset), size);
}

void readData(gr_file_handle file_handle, gr_vfs_handle vfs_handle, char* buffer, size_t size, int64_t offset) {
    EXPECT_EQ(gr_file_pread(vfs_handle, file_handle, buffer, size, offset), size);
}

TEST_F(ComplexGRApiTest, TestConcurrentReadWrite) {
    const int data_size1 = 512 * 1024; // 512KB
    const int data_size2 = 256 * 1024; // 256KB
    char *data1 = new char[data_size1];
    char *data2 = new char[data_size2];
    memset(data1, 'X', data_size1);
    memset(data2, 'Y', data_size2);

    char *read_buffer1 = new char[data_size1];
    char *read_buffer2 = new char[data_size2];

    std::vector<std::thread> threads;

    // 启动并发写线程
    threads.emplace_back(writeData, &file_handle1, g_vfs_handle1, data1, data_size1, 0);
    threads.emplace_back(writeData, &file_handle2, g_vfs_handle2, data2, data_size2, 0);
    // 启动并发读线程

    sleep(5); // 确保写操作先完成
    threads.emplace_back(readData, file_handle3, g_vfs_handle3, read_buffer1, data_size1, 0);
    threads.emplace_back(readData, file_handle4, g_vfs_handle4, read_buffer2, data_size2, 0);

    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }

    // 验证读取的数据是否与写入的数据一致
    EXPECT_EQ(memcmp(data1, read_buffer1, data_size1), 0);
    EXPECT_EQ(memcmp(data2, read_buffer2, data_size2), 0);

    delete[] data1;
    delete[] data2;
    delete[] read_buffer1;
    delete[] read_buffer2;
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}