#include <gtest/gtest.h>
#include <string>
#include "table/runtime/operators/window/internal/LRUMap.h"

TEST(LRUMapTest, DefaultConstructor)
{
    LRUMap<int, std::string> lru;
    EXPECT_FALSE(lru.get(1).has_value());
}

TEST(LRUMapTest, ConstructorWithCapacity)
{
    LRUMap<int, int> lru(5);
    for (int i = 0; i < 10; ++i) {
        lru.put(i, i * 10);
    }
    EXPECT_FALSE(lru.get(0).has_value());
    EXPECT_FALSE(lru.get(1).has_value());
    EXPECT_FALSE(lru.get(2).has_value());
    EXPECT_FALSE(lru.get(3).has_value());
    EXPECT_FALSE(lru.get(4).has_value());
    EXPECT_TRUE(lru.get(5).has_value());
    EXPECT_EQ(lru.get(5).value(), 50);
    EXPECT_TRUE(lru.get(9).has_value());
    EXPECT_EQ(lru.get(9).value(), 90);
}

TEST(LRUMapTest, PutAndGet)
{
    LRUMap<int, std::string> lru;
    lru.put(1, "one");
    lru.put(2, "two");
    lru.put(3, "three");

    auto val1 = lru.get(1);
    EXPECT_TRUE(val1.has_value());
    EXPECT_EQ(val1.value(), "one");

    auto val2 = lru.get(2);
    EXPECT_TRUE(val2.has_value());
    EXPECT_EQ(val2.value(), "two");

    auto val3 = lru.get(3);
    EXPECT_TRUE(val3.has_value());
    EXPECT_EQ(val3.value(), "three");
}

TEST(LRUMapTest, GetNonExistentKey)
{
    LRUMap<int, int> lru;
    lru.put(1, 100);

    auto val = lru.get(999);
    EXPECT_FALSE(val.has_value());
}

TEST(LRUMapTest, UpdateExistingKey)
{
    LRUMap<int, std::string> lru;
    lru.put(1, "one");
    lru.put(1, "ONE");

    auto val = lru.get(1);
    EXPECT_TRUE(val.has_value());
    EXPECT_EQ(val.value(), "ONE");
}

TEST(LRUMapTest, LRUEviction)
{
    LRUMap<int, int> lru(3);

    lru.put(1, 10);
    lru.put(2, 20);
    lru.put(3, 30);
    lru.put(4, 40);

    EXPECT_FALSE(lru.get(1).has_value());
    EXPECT_TRUE(lru.get(2).has_value());
    EXPECT_TRUE(lru.get(3).has_value());
    EXPECT_TRUE(lru.get(4).has_value());
}

TEST(LRUMapTest, LRUOrderOnGet)
{
    LRUMap<int, int> lru(3);

    lru.put(1, 10);
    lru.put(2, 20);
    lru.put(3, 30);

    lru.get(1);

    lru.put(4, 40);

    EXPECT_TRUE(lru.get(1).has_value());
    EXPECT_FALSE(lru.get(2).has_value());
    EXPECT_TRUE(lru.get(3).has_value());
    EXPECT_TRUE(lru.get(4).has_value());
}

TEST(LRUMapTest, LRUOrderOnPut)
{
    LRUMap<int, int> lru(3);

    lru.put(1, 10);
    lru.put(2, 20);
    lru.put(3, 30);

    lru.put(1, 100);

    lru.put(4, 40);

    EXPECT_TRUE(lru.get(1).has_value());
    EXPECT_EQ(lru.get(1).value(), 100);
    EXPECT_FALSE(lru.get(2).has_value());
    EXPECT_TRUE(lru.get(3).has_value());
    EXPECT_TRUE(lru.get(4).has_value());
}

TEST(LRUMapTest, StringKey)
{
    LRUMap<std::string, int> lru(2);

    lru.put("one", 1);
    lru.put("two", 2);
    lru.put("three", 3);

    EXPECT_FALSE(lru.get("one").has_value());
    EXPECT_TRUE(lru.get("two").has_value());
    EXPECT_EQ(lru.get("two").value(), 2);
    EXPECT_TRUE(lru.get("three").has_value());
    EXPECT_EQ(lru.get("three").value(), 3);
}

TEST(LRUMapTest, MultipleGetUpdatesLRU)
{
    LRUMap<int, int> lru(3);

    lru.put(1, 10);
    lru.put(2, 20);
    lru.put(3, 30);

    lru.get(1);
    lru.get(2);

    lru.put(4, 40);

    EXPECT_TRUE(lru.get(1).has_value());
    EXPECT_TRUE(lru.get(2).has_value());
    EXPECT_FALSE(lru.get(3).has_value());
    EXPECT_TRUE(lru.get(4).has_value());
}

TEST(LRUMapTest, OverwriteDoesNotChangeSize)
{
    LRUMap<int, int> lru(2);

    lru.put(1, 10);
    lru.put(2, 20);
    lru.put(1, 100);
    lru.put(1, 1000);

    EXPECT_TRUE(lru.get(1).has_value());
    EXPECT_EQ(lru.get(1).value(), 1000);
    EXPECT_TRUE(lru.get(2).has_value());
    EXPECT_EQ(lru.get(2).value(), 20);
}

TEST(LRUMapTest, CapacityOne)
{
    LRUMap<int, int> lru(1);

    lru.put(1, 10);
    EXPECT_TRUE(lru.get(1).has_value());
    EXPECT_EQ(lru.get(1).value(), 10);

    lru.put(2, 20);
    EXPECT_FALSE(lru.get(1).has_value());
    EXPECT_TRUE(lru.get(2).has_value());
    EXPECT_EQ(lru.get(2).value(), 20);
}