package logger

import (
	"context"
	"fmt"
	"time"

	"gorm.io/gorm/logger"
)

type GormLogger struct {
	SlowThreshold time.Duration
}

const TAG = "[GORM]"

func (l *GormLogger) LogMode(logger.LogLevel) logger.Interface {
	var sysLevel string
	switch logLevel {
	case DebugLevel:
		sysLevel = "debug"
	case InfoLevel:
		sysLevel = "info"
	case SevereLevel:
		sysLevel = "severe"
	case disableLevel:
		sysLevel = "disable"
	default:
		sysLevel = "unknown"
	}
	Debugf("%s System Log Level is %s", TAG, sysLevel)
	return l
}

func (l *GormLogger) Info(ctx context.Context, str string, args ...interface{}) {
	WithContext(ctx).WithCallerSkip(6).Debugf("%s Info: %s", TAG, fmt.Sprintf(str, args...))
}

func (l *GormLogger) Warn(ctx context.Context, str string, args ...interface{}) {
	WithContext(ctx).WithCallerSkip(6).Debugf("%s Warn: %s", TAG, fmt.Sprintf(str, args...))
}

func (l *GormLogger) Error(ctx context.Context, str string, args ...interface{}) {
	WithContext(ctx).WithCallerSkip(6).Errorf("%s Error: %s", TAG, fmt.Sprintf(str, args...))
}

func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	sql, rowsAffected := fc()
	duration := time.Since(begin)
	fields := []LogField{
		{
			Key:   "sql",
			Value: sql,
		},
		{
			Key:   "rows",
			Value: rowsAffected,
		},
	}
	if err != nil {
		fields = append(fields, LogField{
			Key:   "error",
			Value: err.Error(),
		})
		WithContext(ctx).WithCallerSkip(6).WithDuration(duration).Errorw(TAG, fields...)
		return
	}

	if l.SlowThreshold > 0 && duration >= l.SlowThreshold {
		WithContext(ctx).WithCallerSkip(6).WithDuration(duration).Sloww(fmt.Sprintf("%s SQL Slow", TAG), fields...)
		return
	}

	if shallLog(DebugLevel) {
		WithContext(ctx).WithCallerSkip(6).WithDuration(duration).Debugw(fmt.Sprintf("%s SQL Executed", TAG), fields...)
	}
}
