package uiapi

import (
	"testing"
	"time"
)

func TestCacheGetSet(t *testing.T) {
	c := newCache(100 * time.Millisecond)
	defer c.Close()

	// Test set and get
	c.set("key1", "value1")
	val, ok := c.get("key1")
	if !ok {
		t.Error("expected key1 to exist")
	}
	if val != "value1" {
		t.Errorf("expected value1, got %v", val)
	}

	// Test non-existent key
	_, ok = c.get("nonexistent")
	if ok {
		t.Error("expected nonexistent key to return false")
	}
}

func TestCacheExpiry(t *testing.T) {
	c := newCache(50 * time.Millisecond)
	defer c.Close()

	c.set("expiring", "data")

	// Should exist immediately
	_, ok := c.get("expiring")
	if !ok {
		t.Error("expected key to exist immediately after set")
	}

	// Wait for expiry
	time.Sleep(60 * time.Millisecond)

	// Should be expired now
	_, ok = c.get("expiring")
	if ok {
		t.Error("expected key to be expired")
	}
}

func TestCacheInvalidate(t *testing.T) {
	c := newCache(time.Minute)
	defer c.Close()

	c.set("key1", "value1")
	c.set("key2", "value2")

	// Invalidate single key
	c.Invalidate("key1")
	_, ok := c.get("key1")
	if ok {
		t.Error("expected key1 to be invalidated")
	}

	// key2 should still exist
	val, ok := c.get("key2")
	if !ok {
		t.Error("expected key2 to still exist")
	}
	if val != "value2" {
		t.Errorf("expected value2, got %v", val)
	}
}

func TestCacheInvalidateAll(t *testing.T) {
	c := newCache(time.Minute)
	defer c.Close()

	c.set("key1", "value1")
	c.set("key2", "value2")
	c.set("key3", "value3")

	// Invalidate all
	c.InvalidateAll()

	for _, key := range []string{"key1", "key2", "key3"} {
		_, ok := c.get(key)
		if ok {
			t.Errorf("expected %s to be invalidated", key)
		}
	}
}

func TestCacheConcurrency(t *testing.T) {
	c := newCache(time.Second)
	defer c.Close()

	done := make(chan bool)
	go func() {
		for i := 0; i < 1000; i++ {
			c.set("key", i)
		}
		done <- true
	}()
	go func() {
		for i := 0; i < 1000; i++ {
			c.get("key")
		}
		done <- true
	}()

	<-done
	<-done
}

// TestCacheCloseIdempotent verifies Close() can be called multiple times without panic
func TestCacheCloseIdempotent(t *testing.T) {
	c := newCache(time.Second)

	// First close - should work
	c.Close()

	// Second close - should NOT panic (idempotent)
	c.Close()

	// Third close - still should not panic
	c.Close()
}
