#include "gtest/gtest.h"
#include "db/NewDB.h"  // NewDB 的头文件
#include "leveldb/env.h"
#include "leveldb/db.h"
#include <iostream>
#include <random>
#include <ctime>

using namespace leveldb;

Status OpenDB(std::string dbName, NewDB** db) {
    Options options = Options();
    options.create_if_missing = true;
    return NewDB::Open(options, dbName, db);
}


// 全局的随机数引擎
std::default_random_engine rng;

// 设置随机种子
void SetGlobalSeed(unsigned seed) {
    rng.seed(seed);
}

// 生成随机字符串
std::string GenerateRandomString(size_t length) {
    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    std::uniform_int_distribution<int> dist(0, sizeof(alphanum) - 2);

    std::string str(length, 0);
    for (size_t i = 0; i < length; ++i) {
        str[i] = alphanum[dist(rng)];
    }
    return str;
}

std::string testdbname = "dbtest27";

TEST(TestNewDB, CreateIndexAndQueryTest) {
    // 创建 NewDB 实例
    NewDB* db;
    ASSERT_TRUE(OpenDB(testdbname, &db).ok());

    // 批量插入数据
    std::vector<std::pair<std::string, FieldArray>> bulk_data;
    const int num_records = 100;

    for (int i = 0; i < num_records; ++i) {
        std::string key = "k_" + GenerateRandomString(10);
        FieldArray fields = {
            {"name", GenerateRandomString(5)},
            {"address", GenerateRandomString(15)},
            {"phone", GenerateRandomString(11)}
        };
        bulk_data.emplace_back(key, fields);

        ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok());
    }

    // 创建索引字段
    db->CreateIndexOnField("address");

    // 验证插入的数据和索引
    for (const auto& [key, fields] : bulk_data) {
        // 获取并验证字段数据
        FieldArray retrieved_fields;
        ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok());
        EXPECT_EQ(retrieved_fields.size(), fields.size());

        // 验证插入的每个字段
        for (size_t i = 0; i < fields.size(); ++i) {
            EXPECT_EQ(fields[i].first, retrieved_fields[i].first);  // 字段名
            EXPECT_EQ(fields[i].second, retrieved_fields[i].second); // 字段值
        }

        // 验证索引是否能正确找到对应的键
        Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询
        std::vector<std::string> matching_keys = db->QueryByIndex(field_to_query);
        EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键
        EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end());
    }

    delete db;
}



// 测试创建二级索引后批量插入、以及删除索引后的查询
TEST(TestNewDB, PutFieldsAndDeleteIndexTest) {
    // 创建 NewDB 实例
    NewDB* db;
    ASSERT_TRUE(OpenDB(testdbname, &db).ok());

    db->CreateIndexOnField("address");

    // 批量插入数据
    std::vector<std::pair<std::string, FieldArray>> bulk_data;
    const int num_records = 100;

    for (int i = 0; i < num_records; ++i) {
        std::string key = "k_" + GenerateRandomString(10);
        FieldArray fields = {
            {"name", GenerateRandomString(5)},
            {"address", GenerateRandomString(15)},
            {"phone", GenerateRandomString(11)}
        };
        bulk_data.emplace_back(key, fields);

        ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok());
    }

    // 验证插入的数据和索引
    for (const auto& [key, fields] : bulk_data) {
        // 获取并验证字段数据
        FieldArray retrieved_fields;
        ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok());
        EXPECT_EQ(retrieved_fields.size(), fields.size());

        // 验证插入的每个字段
        for (size_t i = 0; i < fields.size(); ++i) {
            EXPECT_EQ(fields[i].first, retrieved_fields[i].first);  // 字段名
            EXPECT_EQ(fields[i].second, retrieved_fields[i].second); // 字段值
        }

        // 验证索引是否能正确找到对应的键
        Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询
        std::vector<std::string> matching_keys = db->QueryByIndex(field_to_query);
        EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键
        EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end());
    }

    // 删除部分数据
    const int num_updates = 20;

    for (int i = 0; i < num_updates; ++i) {
        auto& [key, fields] = bulk_data[i];
        ASSERT_TRUE(db->Delete(WriteOptions(), key));
    }

    for (int i = 0; i < num_updates; ++i) {
        Field query_field{"address", bulk_data[i].second[1].second};
        std::vector<std::string> matching_keys = db->QueryByIndex(query_field);
        EXPECT_TRUE(matching_keys.empty());
    }

    // 删除索引
    ASSERT_TRUE(db->DeleteIndex("address"));

    // 验证删除索引后无法再通过索引查询到数据
    for (const auto& [key, fields] : bulk_data) {
        Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询
        std::vector<std::string> matching_keys = db->QueryByIndex(field_to_query);
        EXPECT_TRUE(matching_keys.empty()); // 索引已被删除，应该找不到任何匹配的键
    }

    delete db;
}


TEST(TestNewDB, UpdateFieldsAndQueryIndexTest) {
    // 创建 NewDB 实例
    NewDB* db;
    ASSERT_TRUE(OpenDB(testdbname, &db).ok());

    // 创建索引字段
    ASSERT_TRUE(db->CreateIndexOnField("address"));

    // 批量插入数据
    const int num_records = 100;
    std::vector<std::pair<std::string, FieldArray>> initial_bulk_data;

    for (int i = 0; i < num_records; ++i) {
        std::string key = "k_" + GenerateRandomString(10);
        FieldArray fields = {
            {"name", GenerateRandomString(5)},
            {"address", GenerateRandomString(15)},
            {"phone", GenerateRandomString(11)}
        };
        initial_bulk_data.emplace_back(key, fields);

        ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok());
    }

    // 验证初始数据的索引查询
    for (const auto& [key, fields] : initial_bulk_data) {
        Field query_field{"address", fields[1].second}; // 使用 address 字段进行查询
        std::vector<std::string> matching_keys = db->QueryByIndex(query_field);
        ASSERT_FALSE(matching_keys.empty()); // 应该能找到对应的键
        EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end());
    }

    // 更新部分数据
    const int num_updates = 20;
    std::vector<std::pair<std::string, FieldArray>> updated_bulk_data;

    for (int i = 0; i < num_updates; ++i) {
        auto& [key, fields] = initial_bulk_data[i];
        FieldArray updated_fields = {
            {"name", fields[0].second},
            {"address", GenerateRandomString(15)}, // 更新 address
            {"phone", fields[2].second}
        };
        updated_bulk_data.emplace_back(key, updated_fields);

        ASSERT_TRUE(db->Put_fields(WriteOptions(), key, updated_fields).ok());
    }

    // 验证更新后的数据和索引
    for (const auto& [key, updated_fields] : updated_bulk_data) {
        // 获取并验证字段数据
        FieldArray retrieved_fields;
        ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok());
        EXPECT_EQ(retrieved_fields.size(), updated_fields.size());

        // 验证插入的每个字段
        for (size_t i = 0; i < updated_fields.size(); ++i) {
            EXPECT_EQ(updated_fields[i].first, retrieved_fields[i].first);  // 字段名
            EXPECT_EQ(updated_fields[i].second, retrieved_fields[i].second); // 字段值
        }

        // 验证新的 address 字段值存在于索引中
        Field query_field_new{"address", updated_fields[1].second};
        std::vector<std::string> matching_keys_new = db->QueryByIndex(query_field_new);
        ASSERT_FALSE(matching_keys_new.empty()); // 新地址应该能找到对应的键
        EXPECT_NE(std::find(matching_keys_new.begin(), matching_keys_new.end(), key), matching_keys_new.end());
    }
    for (int i = 0; i < num_updates; ++i) {
        // 验证旧的 address 字段值不再存在于索引中
        Field query_field_old{"address", initial_bulk_data[i].second[1].second};
        std::vector<std::string> matching_keys_old = db->QueryByIndex(query_field_old);
        EXPECT_TRUE(matching_keys_old.empty()); // 旧地址不应该再找到对应的键
    }

    delete db;
}


int main(int argc, char** argv) {
    // 设置全局随机种子
    SetGlobalSeed(static_cast<unsigned>(time(nullptr)));
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
