package task

import (
	"context"
	"fmt"
	"sync"
	"testing"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/redis/go-redis/v9"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var (
	taskTestDBOnce    sync.Once
	taskTestDB        *gorm.DB
	taskTestDBInitErr error

	taskTestRedisOnce    sync.Once
	taskTestRedis        *redis.Client
	taskTestRedisInitErr error
)

const (
	taskTestDBDSN       = "host=cxd.whcxd.cn port=16159 user=erp_pgsql password=erp_2025 dbname=junhong_cmp_test sslmode=disable TimeZone=Asia/Shanghai"
	taskTestRedisAddr   = "cxd.whcxd.cn:16299"
	taskTestRedisPasswd = "cpNbWtAaqgo1YJmbMp3h"
	taskTestRedisDB     = 15
)

func getTaskTestDB(t *testing.T) *gorm.DB {
	t.Helper()

	taskTestDBOnce.Do(func() {
		var err error
		taskTestDB, err = gorm.Open(postgres.Open(taskTestDBDSN), &gorm.Config{
			Logger: logger.Default.LogMode(logger.Silent),
		})
		if err != nil {
			taskTestDBInitErr = fmt.Errorf("无法连接测试数据库: %w", err)
			return
		}

		err = taskTestDB.AutoMigrate(
			&model.IotCard{},
			&model.IotCardImportTask{},
			&model.Device{},
			&model.DeviceImportTask{},
			&model.DeviceSimBinding{},
		)
		if err != nil {
			taskTestDBInitErr = fmt.Errorf("数据库迁移失败: %w", err)
		}
	})

	if taskTestDBInitErr != nil {
		t.Skipf("跳过测试：%v", taskTestDBInitErr)
	}

	return taskTestDB
}

func getTaskTestRedis(t *testing.T) *redis.Client {
	t.Helper()

	taskTestRedisOnce.Do(func() {
		taskTestRedis = redis.NewClient(&redis.Options{
			Addr:     taskTestRedisAddr,
			Password: taskTestRedisPasswd,
			DB:       taskTestRedisDB,
		})

		ctx := context.Background()
		if err := taskTestRedis.Ping(ctx).Err(); err != nil {
			taskTestRedisInitErr = fmt.Errorf("无法连接 Redis: %w", err)
		}
	})

	if taskTestRedisInitErr != nil {
		t.Skipf("跳过测试：%v", taskTestRedisInitErr)
	}

	return taskTestRedis
}

func newTaskTestTransaction(t *testing.T) *gorm.DB {
	t.Helper()

	db := getTaskTestDB(t)
	tx := db.Begin()
	if tx.Error != nil {
		t.Fatalf("开启测试事务失败: %v", tx.Error)
	}

	t.Cleanup(func() {
		tx.Rollback()
	})

	return tx
}

func cleanTaskTestRedisKeys(t *testing.T, rdb *redis.Client) {
	t.Helper()

	ctx := context.Background()
	testPrefix := fmt.Sprintf("test:%s:", t.Name())

	keys, _ := rdb.Keys(ctx, testPrefix+"*").Result()
	if len(keys) > 0 {
		rdb.Del(ctx, keys...)
	}

	t.Cleanup(func() {
		keys, _ := rdb.Keys(ctx, testPrefix+"*").Result()
		if len(keys) > 0 {
			rdb.Del(ctx, keys...)
		}
	})
}
