// Package testutil 提供项目集成测试共用的真实基础设施连接。
package testutil

import (
	"os"
	"strconv"
	"testing"

	"github.com/break/junhong_cmp_fiber/pkg/config"
	"github.com/break/junhong_cmp_fiber/pkg/database"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// NewPostgresTransaction 创建自动回滚的 PostgreSQL 测试事务。
func NewPostgresTransaction(t *testing.T) *gorm.DB {
	t.Helper()
	db := NewPostgresDatabase(t)
	tx := db.Begin()
	if tx.Error != nil {
		t.Fatalf("开启测试事务失败：%v", tx.Error)
	}
	t.Cleanup(func() { _ = tx.Rollback().Error })
	return tx
}

// NewPostgresDatabase 创建自动关闭、可使用多个连接的 PostgreSQL 测试数据库。
// 仅在需要验证真实并发条件更新时使用；普通集成测试仍优先使用自动回滚事务。
func NewPostgresDatabase(t *testing.T) *gorm.DB {
	t.Helper()
	if os.Getenv("JUNHONG_DATABASE_HOST") == "" {
		t.Skip("未加载 .env.local，跳过依赖真实 PostgreSQL 的集成测试")
	}
	cfg, err := config.Load()
	if err != nil {
		t.Fatalf("加载测试配置失败：%v", err)
	}
	db, err := database.InitPostgreSQL(&cfg.Database, zap.NewNop())
	if err != nil {
		t.Fatalf("连接 PostgreSQL 失败：%v", err)
	}
	t.Cleanup(func() {
		if sqlDB, dbErr := db.DB(); dbErr == nil {
			_ = sqlDB.Close()
		}
	})
	return db
}

// NewRedisClient 创建真实 Redis 测试客户端并在测试结束时关闭。
func NewRedisClient(t *testing.T) *redis.Client {
	t.Helper()
	if os.Getenv("JUNHONG_REDIS_ADDRESS") == "" {
		t.Skip("未加载 .env.local，跳过依赖真实 Redis 的集成测试")
	}
	cfg, err := config.Load()
	if err != nil {
		t.Fatalf("加载测试配置失败：%v", err)
	}
	client, err := database.NewRedisClient(database.RedisConfig{
		Address: cfg.Redis.Address + ":" + strconv.Itoa(cfg.Redis.Port), Password: cfg.Redis.Password,
		DB: cfg.Redis.DB, PoolSize: cfg.Redis.PoolSize, MinIdleConns: cfg.Redis.MinIdleConns,
		DialTimeout: cfg.Redis.DialTimeout, ReadTimeout: cfg.Redis.ReadTimeout, WriteTimeout: cfg.Redis.WriteTimeout,
	}, zap.NewNop())
	if err != nil {
		t.Fatalf("连接 Redis 失败：%v", err)
	}
	t.Cleanup(func() { _ = client.Close() })
	return client
}

// StringPointer 返回字符串值的指针，供测试用例构造 nullable string 参数。
func StringPointer(s string) *string { return &s }
