package service

import (
	"testing"

	"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 setupBillingSyncDB(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
}

// TestNeedsRefundLocked_SyncedUser 测试同步用户在 consumed > 0 时需要退款
func TestNeedsRefundLocked_SyncedUser(t *testing.T) {
	setupBillingSyncDB(t)

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

	require.NoError(t, model.DB.Create(&model.User{Id: 100, Username: "test-nr", Source: common.UserSourceSynced, SyncedQuota: 500000}).Error)
	f := NewSyncedUserFunding(100, 200, "req-nr-001", 500000)
	require.NoError(t, f.PreConsume(5000))

	session := &BillingSession{
		funding: f,
	}
	assert.True(t, session.needsRefundLocked())
}

// TestNeedsRefundLocked_SyncedUser_NoConsumed 测试同步用户在 consumed == 0 时不需要退款
func TestNeedsRefundLocked_SyncedUser_NoConsumed(t *testing.T) {
	setupBillingSyncDB(t)

	f := NewSyncedUserFunding(100, 200, "req-nr-002", 500000)

	session := &BillingSession{
		funding: f,
	}
	assert.False(t, session.needsRefundLocked())
}

// TestNeedsRefundLocked_SyncedUser_FundingSettled 测试 fundingSettled=true 后不需要退款
func TestNeedsRefundLocked_SyncedUser_FundingSettled(t *testing.T) {
	setupBillingSyncDB(t)

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

	require.NoError(t, model.DB.Create(&model.User{Id: 100, Username: "test-nr3", Source: common.UserSourceSynced, SyncedQuota: 500000}).Error)
	f := NewSyncedUserFunding(100, 200, "req-nr-003", 500000)
	require.NoError(t, f.PreConsume(5000))

	session := &BillingSession{
		funding:        f,
		fundingSettled: true, // 资金已提交
	}
	// fundingSettled=true 时不应再退
	assert.False(t, session.needsRefundLocked())
}

// TestShouldTrust_SyncedUser_SourceNotWalletOrSub 验证同步用户 Source 不是 wallet/subscription，
// 因此在 shouldTrust 的 switch 中走 default 分支返回 false
func TestShouldTrust_SyncedUser_SourceNotWalletOrSub(t *testing.T) {
	f := NewSyncedUserFunding(100, 200, "req-trust", 500000)
	assert.Equal(t, "synced_wallet", f.Source())
	assert.NotEqual(t, BillingSourceWallet, f.Source())
	assert.NotEqual(t, BillingSourceSubscription, f.Source())
}

// TestSyncedUserFunding_BillingSource 测试同步用户计费来源标识
func TestSyncedUserFunding_BillingSource(t *testing.T) {
	f := NewSyncedUserFunding(100, 200, "req-src", 500000)
	assert.Equal(t, BillingSourceSyncedWallet, f.Source())
	assert.Equal(t, "synced_wallet", f.Source())
}

// TestNeedsRefundLocked_WalletAndSynced 对比钱包和同步用户的行为
func TestNeedsRefundLocked_WalletAndSynced(t *testing.T) {
	// 钱包用户：tokenConsumed > 0 才需要退
	walletSession := &BillingSession{
		funding:       &WalletFunding{userId: 1, consumed: 100},
		tokenConsumed: 100,
	}
	assert.True(t, walletSession.needsRefundLocked())

	walletSessionZero := &BillingSession{
		funding:       &WalletFunding{userId: 1, consumed: 100},
		tokenConsumed: 0,
	}
	assert.False(t, walletSessionZero.needsRefundLocked())

	// 同步用户：consumed > 0 就需要退（即使 tokenConsumed=0）
	setupBillingSyncDB(t)
	settings := system_setting.GetRegionSyncSettings()
	origThreshold := settings.MinBalanceThreshold
	defer func() { settings.MinBalanceThreshold = origThreshold }()
	settings.MinBalanceThreshold = 100000

	require.NoError(t, model.DB.Create(&model.User{Id: 100, Username: "test-compare", Source: common.UserSourceSynced, SyncedQuota: 500000}).Error)
	syncF := NewSyncedUserFunding(100, 200, "req-compare", 500000)
	require.NoError(t, syncF.PreConsume(5000))

	syncSession := &BillingSession{
		funding:       syncF,
		tokenConsumed: 0, // tokenConsumed=0 但 consumed > 0
	}
	assert.True(t, syncSession.needsRefundLocked())
}
