package gormutil

import (
	"context"
	"fmt"
	"time"

	"github.com/pingcap/log"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// loggerAdapter implements the gorm logger.Interface.
type loggerAdapter struct {
	enableTrace bool
	level       logger.LogLevel
}

// LogMode implements the logger.Interface interface
func (l *loggerAdapter) LogMode(level logger.LogLevel) logger.Interface {
	l.level = level
	return l
}

// Info implements the logger.Interface interface
func (l *loggerAdapter) Info(_ context.Context, format string, args ...interface{}) {
	if l.level < logger.Info {
		return
	}
	log.L().Info(fmt.Sprintf(format, args...))
}

// Warn implements the logger.Interface interface
func (l *loggerAdapter) Warn(_ context.Context, format string, args ...interface{}) {
	if l.level < logger.Warn {
		return
	}
	log.L().Warn(fmt.Sprintf(format, args...))
}

// Error implements the logger.Interface interface
func (l *loggerAdapter) Error(_ context.Context, format string, args ...interface{}) {
	if l.level < logger.Error {
		return
	}
	log.L().Error(fmt.Sprintf(format, args...))
}

// Trace implements the logger.Interface interface
func (l *loggerAdapter) Trace(_ context.Context, _ time.Time, fc func() (string, int64), err error) {
	if l.enableTrace || err != nil {
		sql, _ := fc()
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				log.L().Info("GORM Trace", zap.String("SQL", sql))
			} else {
				log.L().Error("GORM Trace", zap.String("SQL", sql), zap.Error(err))
			}
		} else {
			log.L().Debug("GORM Trace", zap.String("SQL", sql), zap.Error(err))
		}
	}
}
