package logger

import (
	"context"
	"errors"
	"fmt"
	"git.nspix.com/golang/micro/log"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/utils"
	"time"
)

type Logger struct {
	LogLevel      logger.LogLevel
	SlowThreshold time.Duration
}

func (l Logger) LogMode(level logger.LogLevel) logger.Interface {
	l.LogLevel = level
	return l
}

func (l Logger) Info(ctx context.Context, s string, i ...interface{}) {
	log.Infof("[SQL] "+s, i...)
}

func (l Logger) Warn(ctx context.Context, s string, i ...interface{}) {
	log.Warnf("[SQL] "+s, i...)
}

func (l Logger) Error(ctx context.Context, s string, i ...interface{}) {
	log.Errorf("[SQL] "+s, i...)
}

func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	elapsed := time.Since(begin)
	switch {
	case err != nil && l.LogLevel >= logger.Error && (!errors.Is(err, gorm.ErrRecordNotFound)):
		sql, rows := fc()
		if rows == -1 {
			l.Error(ctx, "%s %s", sql, err.Error())
		} else {
			l.Error(ctx, "%s %s", sql, err.Error())
		}
	case elapsed > l.SlowThreshold && l.SlowThreshold != 0:
		sql, _ := fc()
		slowLog := fmt.Sprintf("slow sql [%s] spend %s in %s", sql, elapsed, utils.FileWithLineNum())
		l.Warn(ctx, slowLog)
	case l.LogLevel == logger.Info:
		sql, rows := fc()
		if rows == -1 {
			log.Debugf("[SQL] %s", sql)
		} else {
			log.Debugf("[SQL] %s: %d", sql, rows)
		}
	}
}

func NewGormLogger() *Logger {
	return &Logger{SlowThreshold: time.Second * 20}
}
