package testenv

import (
	"context"
	"testing"
	"time"

	"github.com/testcontainers/testcontainers-go"
	tcnetwork "github.com/testcontainers/testcontainers-go/network"
	"github.com/testcontainers/testcontainers-go/wait"
)

// Redis holds a running Redis testcontainer reachable from the host
// via HostAddr and from within the shared Docker network at the alias
// "redis". Password is the requirepass value the test container was
// started with so callers can pass it to gateway via env.
type Redis struct {
	container testcontainers.Container
	HostAddr  string
	Password  string
}

// RedisIntegrationPassword is the fixed requirepass value used by all
// integration scenarios. Surface it as a constant so test envs can
// agree on it without per-instance plumbing.
const RedisIntegrationPassword = "integration-redis-pw"

// StartRedis starts a redis:7-alpine container attached to network.
// The gateway uses Redis for anti-replay reservations only.
func StartRedis(t *testing.T, network string) *Redis {
	t.Helper()
	ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
	defer cancel()

	req := testcontainers.ContainerRequest{
		Image:        "redis:7-alpine",
		ExposedPorts: []string{"6379/tcp"},
		Cmd:          []string{"redis-server", "--requirepass", RedisIntegrationPassword},
		WaitingFor:   wait.ForLog("Ready to accept connections"),
	}
	gcr := &testcontainers.GenericContainerRequest{ContainerRequest: req}
	if network != "" {
		_ = tcnetwork.WithNetwork([]string{"redis"}, &testcontainers.DockerNetwork{Name: network}).Customize(gcr)
	}
	gcr.Started = true
	container, err := testcontainers.GenericContainer(ctx, *gcr)
	if err != nil {
		t.Skipf("redis testcontainer unavailable: %v", err)
	}
	t.Cleanup(func() {
		if err := testcontainers.TerminateContainer(container); err != nil {
			t.Logf("terminate redis: %v", err)
		}
	})

	host, err := container.Host(ctx)
	if err != nil {
		t.Fatalf("redis host: %v", err)
	}
	mapped, err := container.MappedPort(ctx, "6379/tcp")
	if err != nil {
		t.Fatalf("redis port: %v", err)
	}
	return &Redis{
		container: container,
		HostAddr:  HostPort(host, int(mapped.Num())),
		Password:  RedisIntegrationPassword,
	}
}
