package service

import (
	"testing"
	"time"

	"github.com/QuantumNous/new-api/common"
	"github.com/QuantumNous/new-api/model"
	"github.com/QuantumNous/new-api/setting/system_setting"
	"github.com/glebarez/sqlite"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gorm.io/gorm"
)

func setupSyncedFundingDB(t *testing.T) *gorm.DB {
	t.Helper()
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err)
	sqlDB, _ := db.DB()
	sqlDB.SetMaxOpenConns(1)

	origDB := model.DB
	origLogDB := model.LOG_DB
	model.DB = db
	model.LOG_DB = db
	common.UsingSQLite = true
	common.RedisEnabled = false

	require.NoError(t, db.AutoMigrate(&model.PendingSyncRecord{}, &model.User{}))

	t.Cleanup(func() {
		model.DB = origDB
		model.LOG_DB = origLogDB
		sqlDB.Close()
	})
	return db
}

func TestNewSyncedUserFunding(t *testing.T) {
	f := NewSyncedUserFunding(100, 200, "req-001", 500000)
	assert.Equal(t, 100, f.userId)
	assert.Equal(t, 200, f.remoteUserId)
	assert.Equal(t, "req-001", f.requestId)
	assert.Equal(t, 500000, f.syncedQuota)
	assert.Equal(t, 0, f.consumed)
}

func TestSyncedUserFunding_Source(t *testing.T) {
	f := NewSyncedUserFunding(100, 200, "req-001", 500000)
	assert.Equal(t, BillingSourceSyncedWallet, f.Source())
}

func TestPreConsume_Success(t *testing.T) {
	setupSyncedFundingDB(t)

	settings := system_setting.GetRegionSyncSettings()
	origThreshold := settings.MinBalanceThreshold
	settings.MinBalanceThreshold = 100000
	defer func() { settings.MinBalanceThreshold = origThreshold }()

	// 创建测试用户（AtomicDecreaseSyncedQuota 操作 DB 中的 synced_quota）
	require.NoError(t, model.DB.Create(&model.User{
		Id: 100, Username: "test-synced", Source: common.UserSourceSynced, SyncedQuota: 1000000,
	}).Error)

	f := NewSyncedUserFunding(100, 200, "req-pre-success", 1000000)
	err := f.PreConsume(50000)
	require.NoError(t, err)
	assert.Equal(t, 50000, f.consumed)

	// 验证 PendingSyncRecord 已创建
	var record model.PendingSyncRecord
	require.NoError(t, model.DB.Where("request_id = ?", "req-pre-success").First(&record).Error)
	assert.Equal(t, 100, record.UserId)
	assert.Equal(t, 200, record.RemoteUserId)
	assert.Equal(t, 50000, record.Quota)
	assert.Equal(t, model.PendingSyncStatusPending, record.Status)
}

func TestPreConsume_ZeroAmount(t *testing.T) {
	setupSyncedFundingDB(t)

	f := NewSyncedUserFunding(100, 200, "req-pre-zero", 1000000)
	err := f.PreConsume(0)
	assert.NoError(t, err)
	assert.Equal(t, 0, f.consumed)
}

func TestPreConsume_NegativeAmount(t *testing.T) {
	setupSyncedFundingDB(t)

	f := NewSyncedUserFunding(100, 200, "req-pre-neg", 1000000)
	err := f.PreConsume(-100)
	assert.NoError(t, err)
	assert.Equal(t, 0, f.consumed)
}

func TestPreConsume_InsufficientQuota(t *testing.T) {
	setupSyncedFundingDB(t)

	settings := system_setting.GetRegionSyncSettings()
	origThreshold := settings.MinBalanceThreshold
	settings.MinBalanceThreshold = 100000
	defer func() { settings.MinBalanceThreshold = origThreshold }()

	require.NoError(t, model.DB.Create(&model.User{
		Id: 100, Username: "test-insuf", Source: common.UserSourceSynced, SyncedQuota: 149999,
	}).Error)

	// syncedQuota=149999, amount=50000, threshold=100000
	// 149999 < 50000 + 100000 = 150000 → 不满足
	f := NewSyncedUserFunding(100, 200, "req-pre-insuf", 149999)
	err := f.PreConsume(50000)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "余额不足")
	assert.Equal(t, 0, f.consumed)
}

func TestPreConsume_ExactlyAtThreshold(t *testing.T) {
	setupSyncedFundingDB(t)

	settings := system_setting.GetRegionSyncSettings()
	origThreshold := settings.MinBalanceThreshold
	settings.MinBalanceThreshold = 100000
	defer func() { settings.MinBalanceThreshold = origThreshold }()

	require.NoError(t, model.DB.Create(&model.User{
		Id: 100, Username: "test-exact", Source: common.UserSourceSynced, SyncedQuota: 150000,
	}).Error)

	// syncedQuota=150000, amount=50000, threshold=100000
	// 150000 >= 50000 + 100000 = 150000 → 刚好满足
	f := NewSyncedUserFunding(100, 200, "req-pre-exact", 150000)
	err := f.PreConsume(50000)
	assert.NoError(t, err)
	assert.Equal(t, 50000, f.consumed)
}

func TestSettle_PositiveDelta(t *testing.T) {
	setupSyncedFundingDB(t)

	f := NewSyncedUserFunding(100, 200, "req-settle-pos", 500000)
	f.consumed = 1000

	err := f.Settle(500)
	assert.NoError(t, err)
	assert.Equal(t, 1500, f.consumed)
	assert.Equal(t, 499500, f.syncedQuota) // 500000 - 500
}

func TestSettle_NegativeDelta(t *testing.T) {
	setupSyncedFundingDB(t)

	f := NewSyncedUserFunding(100, 200, "req-settle-neg", 500000)
	f.consumed = 1000

	err := f.Settle(-300)
	assert.NoError(t, err)
	assert.Equal(t, 700, f.consumed)
	assert.Equal(t, 500300, f.syncedQuota) // 500000 - (-300) = 500000 + 300
}

func TestSettle_ZeroDelta(t *testing.T) {
	f := NewSyncedUserFunding(100, 200, "req-settle-zero", 500000)
	f.consumed = 1000

	err := f.Settle(0)
	assert.NoError(t, err)
	assert.Equal(t, 1000, f.consumed)      // 不变
	assert.Equal(t, 500000, f.syncedQuota) // 不变
}

func TestSettle_TransitionsPendingToSettled(t *testing.T) {
	db := setupSyncedFundingDB(t)

	// 先创建 pending 记录
	require.NoError(t, model.CreatePendingSyncRecord(100, 200, "req-settle-trans", 1000, 1000))

	f := NewSyncedUserFunding(100, 200, "req-settle-trans", 500000)
	f.consumed = 1000

	err := f.Settle(-300) // 实际消费 700，退还 300
	assert.NoError(t, err)
	assert.Equal(t, 700, f.consumed)

	// 验证记录状态从 pending 转为 settled，quota 更新为实际消费
	var record model.PendingSyncRecord
	require.NoError(t, db.Where("request_id = ?", "req-settle-trans").First(&record).Error)
	assert.Equal(t, model.PendingSyncStatusSettled, record.Status)
	assert.Equal(t, 700, record.Quota)
}

func TestRefund_Success(t *testing.T) {
	db := setupSyncedFundingDB(t)

	// 创建测试用户
	require.NoError(t, model.DB.Create(&model.User{
		Id: 100, Username: "test-refund", Source: common.UserSourceSynced, SyncedQuota: 500000,
	}).Error)

	// 先创建一条 pending 记录
	require.NoError(t, model.CreatePendingSyncRecord(100, 200, "req-refund-ok", 5000, 5000))

	f := NewSyncedUserFunding(100, 200, "req-refund-ok", 500000)
	f.consumed = 5000

	err := f.Refund()
	assert.NoError(t, err)

	// 验证记录已被标记为 synced
	var record model.PendingSyncRecord
	require.NoError(t, db.Where("request_id = ?", "req-refund-ok").First(&record).Error)
	assert.Equal(t, model.PendingSyncStatusSynced, record.Status)
	assert.NotZero(t, record.SyncedAt)
}

func TestRefund_NoConsumed(t *testing.T) {
	setupSyncedFundingDB(t)

	f := NewSyncedUserFunding(100, 200, "req-refund-nocons", 500000)
	f.consumed = 0

	err := f.Refund()
	assert.NoError(t, err)
}

func TestRefund_RecordNotFound(t *testing.T) {
	setupSyncedFundingDB(t)

	// 没有 PendingSyncRecord，但 consumed > 0
	f := NewSyncedUserFunding(100, 200, "req-refund-notfound", 500000)
	f.consumed = 5000

	err := f.Refund()
	assert.NoError(t, err) // 应优雅处理，不报错
}

func TestRefund_RecordAlreadySynced(t *testing.T) {
	db := setupSyncedFundingDB(t)

	// 创建已 synced 的记录
	require.NoError(t, db.Create(&model.PendingSyncRecord{
		UserId: 100, RemoteUserId: 200, RequestId: "req-refund-synced",
		Quota: 5000, Status: model.PendingSyncStatusSynced,
		SyncedAt: time.Now().Unix(), CreatedAt: time.Now().Unix(),
	}).Error)

	f := NewSyncedUserFunding(100, 200, "req-refund-synced", 500000)
	f.consumed = 5000

	err := f.Refund()
	assert.NoError(t, err) // status=pending 不匹配，优雅处理
}
