package httpgateway

import (
	"context"
	"fmt"
	"time"

	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

func (g *HttpGateway) GCSession() {
	ctx := context.Background()
	logger := log.WithContextL(ctx)
	logger.Info("GCSession start")

	txnCount := 0
	txnCleanedCount := 0
	g.sessionStore.RangeTxn(func(session string, txn *TxnSession) bool {
		cleaned := txn.tryToCleanTxn(ctx)
		if cleaned {
			txnCleanedCount++
		}
		txnCount++
		return true
	})

	nonTxnCount := 0
	nonTxnCleanedCount := 0
	g.sessionStore.RangeNonTxn(func(session string, nonTxn *NonTxnSession) bool {
		cleaned := nonTxn.tryToCleanNonTxn(ctx)
		if cleaned {
			nonTxnCleanedCount++
		}
		nonTxnCount++
		return true
	})

	poolCount := 0
	poolCleanedCount := 0
	g.poolManager.Range(func(key string, dbPool *DBPool) bool {
		// it may race for example: after judge inUse == 0, a new request comes and use the db pool
		// but this does not matter, just let new request failed.
		if time.Now().After(dbPool.expire) && dbPool.db.Stats().InUse == 0 {
			logger.Info("db pool closed", zap.String("user", dbPool.cred.Username), zap.String("database", dbPool.cred.Database))
			if err := dbPool.db.Close(); err != nil {
				logger.Error("failed to close db pool", zap.Error(err))
			} else {
				g.poolManager.DeletePool(key)
				poolCleanedCount++
			}
		}
		poolCount++
		return true
	})

	logger.Info(fmt.Sprintf("GCSession finished, txn cleaned total: %d/%d, non-txn cleaned total: %d/%d, pool cleaned total: %d/%d",
		txnCleanedCount, txnCount, nonTxnCleanedCount, nonTxnCount, poolCleanedCount, poolCount))
}
