package proxy

import (
	"net/http/httputil"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestGetTiBRProxy(t *testing.T) {
	// Reset global state for tests
	tibrProxyTTLCache = nil
	initOnce = sync.Once{}
	tibrProxyTTLCacheTTL = 1 * time.Second
	tibrProxyTTLCacheCapacity = 2

	host := "https://example.com"

	t.Run("initialization", func(t *testing.T) {
		proxy := getTiBRProxy(host)
		require.NotNil(t, proxy)
		assert.NotNil(t, tibrProxyTTLCache, "cache should be initialized")
	})

	t.Run("caching behavior", func(t *testing.T) {
		// First call should create new proxy
		proxy1 := getTiBRProxy(host)
		require.NotNil(t, proxy1)

		// Second call should return cached proxy
		proxy2 := getTiBRProxy(host)
		assert.Equal(t, proxy1, proxy2, "should return cached proxy")

		// Wait for cache to expire
		time.Sleep(2 * time.Second)

		// New call after expiration should create new proxy
		proxy3 := getTiBRProxy(host)
		assert.NotEqual(t, proxy1, proxy3, "should create new proxy after TTL")
	})

	t.Run("concurrent access", func(t *testing.T) {
		var wg sync.WaitGroup
		proxies := make([]*httputil.ReverseProxy, 10)

		for i := 0; i < 10; i++ {
			wg.Add(1)
			go func(idx int) {
				defer wg.Done()
				proxies[idx] = getTiBRProxy(host)
			}(i)
		}
		wg.Wait()

		// All returned proxies should be the same instance
		for i := 1; i < 10; i++ {
			assert.Equal(t, proxies[0], proxies[i], "all concurrent calls should get same proxy instance")
		}
	})

	t.Run("cache capacity", func(t *testing.T) {
		url1 := "http://host1:1234"
		url2 := "http://host2:1234"
		url3 := "http://host3:1234"

		// Fill cache to capacity
		getTiBRProxy(url1)
		getTiBRProxy(url2)

		// Verify both are cached
		assert.Equal(t, 2, tibrProxyTTLCache.Len(), "cache should be at capacity")

		// Add third item should evict one
		getTiBRProxy(url3)
		assert.Equal(t, 2, tibrProxyTTLCache.Len(), "cache should not exceed capacity")
	})
}
