package testutils

import (
	"context"
	"sync"

	"github.com/redis/go-redis/v9"
	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/wait"
	"go.uber.org/zap"
)

var (
	redisContainer testcontainers.Container
	redisClient    *redis.Client
	redisOnce      sync.Once
	redisErr       error
)

// GetTestRedisClient ensures the Redis container is running and returns a client.
// It uses a singleton pattern to start the container only once per test run.
func GetTestRedisClient(ctx context.Context) (*redis.Client, error) {
	redisOnce.Do(func() {
		redisErr = setupRedisContainer(ctx)
	})
	return redisClient, redisErr
}

func setupRedisContainer(ctx context.Context) error {
	logger := zap.NewNop()
	if zap.L() != nil {
		logger = zap.L()
	}

	logger.Info("Starting Redis testcontainer")

	req := testcontainers.ContainerRequest{
		Image:        "redis:7-alpine",
		ExposedPorts: []string{"6379/tcp"},
		WaitingFor:   wait.ForLog("Ready to accept connections"),
	}

	var containerErr error
	redisContainer, containerErr = testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})

	if containerErr != nil {
		logger.Error("Failed to start Redis testcontainer", zap.Error(containerErr))
		return containerErr
	}

	endpoint, err := redisContainer.Endpoint(ctx, "")
	if err != nil {
		return err
	}

	redisClient = redis.NewClient(&redis.Options{
		Addr: endpoint,
	})

	// Wait for Redis to be ready
	if err := redisClient.Ping(ctx).Err(); err != nil {
		return err
	}

	logger.Info("Redis testcontainer started successfully")
	return nil
}

// TerminateRedisContainer allows manual termination if needed (mostly for cleanup)
func TerminateRedisContainer(ctx context.Context) error {
	if redisContainer != nil {
		return redisContainer.Terminate(ctx)
	}
	return nil
}
