//go:build legacytests
// +build legacytests

package integration

import (
	"context"
	"database/sql"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"quyun/v2/app/config"
	"quyun/v2/app/database"
)

// TestUser 测试用户模型
type TestUser struct {
	ID        int       `gorm:"primaryKey"`
	Name      string    `gorm:"size:100;not null"`
	Email     string    `gorm:"size:100;unique;not null"`
	CreatedAt time.Time `gorm:"autoCreateTime"`
	UpdatedAt time.Time `gorm:"autoUpdateTime"`
}

// TestDatabaseConnection 测试数据库连接
func TestDatabaseConnection(t *testing.T) {
	Convey("数据库连接测试", t, func() {
		var db *gorm.DB
		var sqlDB *sql.DB
		var testConfig *config.Config
		var testDBName string

		Convey("当准备测试数据库时", func() {
			testDBName = "v2_test_integration"
			testConfig = &config.Config{
				Database: config.DatabaseConfig{
					Host:            "localhost",
					Port:            5432,
					Database:        testDBName,
					Username:        "postgres",
					Password:        "password",
					SslMode:         "disable",
					MaxIdleConns:    5,
					MaxOpenConns:    20,
					ConnMaxLifetime: 30 * time.Minute,
				},
			}

			Convey("应该能够连接到数据库", func() {
				dsn := testConfig.Database.GetDSN()
				var err error
				db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
				So(err, ShouldBeNil)
				So(db, ShouldNotBeNil)

				sqlDB, err = db.DB()
				So(err, ShouldBeNil)
				So(sqlDB, ShouldNotBeNil)

				// 设置连接池
				sqlDB.SetMaxIdleConns(testConfig.Database.MaxIdleConns)
				sqlDB.SetMaxOpenConns(testConfig.Database.MaxOpenConns)
				sqlDB.SetConnMaxLifetime(testConfig.Database.ConnMaxLifetime)

				// 测试连接
				err = sqlDB.Ping()
				So(err, ShouldBeNil)
			})

			Convey("应该能够创建测试表", func() {
				err := db.Exec(`
					CREATE TABLE IF NOT EXISTS integration_test_users (
						id SERIAL PRIMARY KEY,
						name VARCHAR(100) NOT NULL,
						email VARCHAR(100) UNIQUE NOT NULL,
						created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
						updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
					)
				`).Error
				So(err, ShouldBeNil)
			})
		})

		Convey("当测试数据库操作时", func() {
			Convey("应该能够创建记录", func() {
				user := TestUser{
					Name:  "Integration Test User",
					Email: "integration@example.com",
				}

				result := db.Create(&user)
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 1)
				So(user.ID, ShouldBeGreaterThan, 0)
			})

			Convey("应该能够查询记录", func() {
				// 先插入测试数据
				user := TestUser{
					Name:  "Query Test User",
					Email: "query@example.com",
				}
				db.Create(&user)

				// 查询记录
				var result TestUser
				err := db.First(&result, "email = ?", "query@example.com").Error
				So(err, ShouldBeNil)
				So(result.Name, ShouldEqual, "Query Test User")
				So(result.Email, ShouldEqual, "query@example.com")
			})

			Convey("应该能够更新记录", func() {
				// 先插入测试数据
				user := TestUser{
					Name:  "Update Test User",
					Email: "update@example.com",
				}
				db.Create(&user)

				// 更新记录
				result := db.Model(&user).Update("name", "Updated Integration User")
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 1)

				// 验证更新
				var updatedUser TestUser
				err := db.First(&updatedUser, user.ID).Error
				So(err, ShouldBeNil)
				So(updatedUser.Name, ShouldEqual, "Updated Integration User")
			})

			Convey("应该能够删除记录", func() {
				// 先插入测试数据
				user := TestUser{
					Name:  "Delete Test User",
					Email: "delete@example.com",
				}
				db.Create(&user)

				// 删除记录
				result := db.Delete(&user)
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 1)

				// 验证删除
				var deletedUser TestUser
				err := db.First(&deletedUser, user.ID).Error
				So(err, ShouldEqual, gorm.ErrRecordNotFound)
			})
		})

		Convey("当测试事务时", func() {
			Convey("应该能够执行事务操作", func() {
				// 开始事务
				tx := db.Begin()
				So(tx, ShouldNotBeNil)

				// 在事务中插入数据
				user := TestUser{
					Name:  "Transaction Test User",
					Email: "transaction@example.com",
				}
				result := tx.Create(&user)
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 1)

				// 查询事务中的数据
				var count int64
				tx.Model(&TestUser{}).Count(&count)
				So(count, ShouldEqual, 1)

				// 提交事务
				err := tx.Commit().Error
				So(err, ShouldBeNil)

				// 验证数据已提交
				db.Model(&TestUser{}).Count(&count)
				So(count, ShouldBeGreaterThan, 0)
			})

			Convey("应该能够回滚事务", func() {
				// 开始事务
				tx := db.Begin()

				// 在事务中插入数据
				user := TestUser{
					Name:  "Rollback Test User",
					Email: "rollback@example.com",
				}
				tx.Create(&user)

				// 回滚事务
				err := tx.Rollback().Error
				So(err, ShouldBeNil)

				// 验证数据已回滚
				var count int64
				db.Model(&TestUser{}).Where("email = ?", "rollback@example.com").Count(&count)
				So(count, ShouldEqual, 0)
			})
		})

		Convey("当测试批量操作时", func() {
			Convey("应该能够批量插入记录", func() {
				users := []TestUser{
					{Name: "Batch User 1", Email: "batch1@example.com"},
					{Name: "Batch User 2", Email: "batch2@example.com"},
					{Name: "Batch User 3", Email: "batch3@example.com"},
				}

				result := db.Create(&users)
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 3)

				// 验证批量插入
				var count int64
				db.Model(&TestUser{}).Where("email LIKE ?", "batch%@example.com").Count(&count)
				So(count, ShouldEqual, 3)
			})

			Convey("应该能够批量更新记录", func() {
				// 先插入测试数据
				users := []TestUser{
					{Name: "Batch Update 1", Email: "batchupdate1@example.com"},
					{Name: "Batch Update 2", Email: "batchupdate2@example.com"},
				}
				db.Create(&users)

				// 批量更新
				result := db.Model(&TestUser{}).
					Where("email LIKE ?", "batchupdate%@example.com").
					Update("name", "Batch Updated User")
				So(result.Error, ShouldBeNil)
				So(result.RowsAffected, ShouldEqual, 2)

				// 验证更新
				var updatedCount int64
				db.Model(&TestUser{}).
					Where("name = ?", "Batch Updated User").
					Count(&updatedCount)
				So(updatedCount, ShouldEqual, 2)
			})
		})

		Convey("当测试查询条件时", func() {
			Convey("应该能够使用各种查询条件", func() {
				// 插入测试数据
				testUsers := []TestUser{
					{Name: "Alice", Email: "alice@example.com"},
					{Name: "Bob", Email: "bob@example.com"},
					{Name: "Charlie", Email: "charlie@example.com"},
					{Name: "Alice Smith", Email: "alice.smith@example.com"},
				}
				db.Create(&testUsers)

				Convey("应该能够使用 LIKE 查询", func() {
					var users []TestUser
					err := db.Where("name LIKE ?", "Alice%").Find(&users).Error
					So(err, ShouldBeNil)
					So(len(users), ShouldEqual, 2)
				})

				Convey("应该能够使用 IN 查询", func() {
					var users []TestUser
					err := db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users).Error
					So(err, ShouldBeNil)
					So(len(users), ShouldEqual, 2)
				})

				Convey("应该能够使用 BETWEEN 查询", func() {
					var users []TestUser
					err := db.Where("id BETWEEN ? AND ?", 1, 3).Find(&users).Error
					So(err, ShouldBeNil)
					So(len(users), ShouldBeGreaterThan, 0)
				})

				Convey("应该能够使用多条件查询", func() {
					var users []TestUser
					err := db.Where("name LIKE ? AND email LIKE ?", "%Alice%", "%example.com").Find(&users).Error
					So(err, ShouldBeNil)
					So(len(users), ShouldEqual, 2)
				})
			})
		})

		Reset(func() {
			// 清理测试表
			if db != nil {
				db.Exec("DROP TABLE IF EXISTS integration_test_users")
			}
			// 关闭数据库连接
			if sqlDB != nil {
				sqlDB.Close()
			}
		})
	})
}

// TestDatabaseConnectionPool 测试数据库连接池
func TestDatabaseConnectionPool(t *testing.T) {
	Convey("数据库连接池测试", t, func() {
		var db *gorm.DB
		var sqlDB *sql.DB

		Convey("当配置连接池时", func() {
			testConfig := &config.Config{
				Database: config.DatabaseConfig{
					Host:            "localhost",
					Port:            5432,
					Database:        "v2_test_pool",
					Username:        "postgres",
					Password:        "password",
					SslMode:         "disable",
					MaxIdleConns:    5,
					MaxOpenConns:    10,
					ConnMaxLifetime: 5 * time.Minute,
				},
			}

			dsn := testConfig.Database.GetDSN()
			var err error
			db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
			So(err, ShouldBeNil)

			sqlDB, err = db.DB()
			So(err, ShouldBeNil)

			Convey("应该能够设置连接池参数", func() {
				sqlDB.SetMaxIdleConns(testConfig.Database.MaxIdleConns)
				sqlDB.SetMaxOpenConns(testConfig.Database.MaxOpenConns)
				sqlDB.SetConnMaxLifetime(testConfig.Database.ConnMaxLifetime)

				// 验证设置
				stats := sqlDB.Stats()
				So(stats.MaxOpenConns, ShouldEqual, testConfig.Database.MaxOpenConns)
				So(stats.MaxIdleConns, ShouldEqual, testConfig.Database.MaxIdleConns)
			})

			Convey("应该能够监控连接池状态", func() {
				// 获取初始状态
				initialStats := sqlDB.Stats()
				So(initialStats.OpenConnections, ShouldEqual, 0)

				// 执行一些查询来创建连接
				for i := 0; i < 3; i++ {
					sqlDB.Ping()
				}

				// 获取使用后的状态
				afterStats := sqlDB.Stats()
				So(afterStats.OpenConnections, ShouldBeGreaterThan, 0)
				So(afterStats.InUse, ShouldBeGreaterThan, 0)
			})
		})

		Reset(func() {
			// 关闭数据库连接
			if sqlDB != nil {
				sqlDB.Close()
			}
		})
	})
}
