package logger

import (
	
	
	
	
	
	
	

	
)

// ErrRecordNotFound record not found error
var ErrRecordNotFound = errors.New("record not found")

// Colors
const (
	Reset       = "\033[0m"
	Red         = "\033[31m"
	Green       = "\033[32m"
	Yellow      = "\033[33m"
	Blue        = "\033[34m"
	Magenta     = "\033[35m"
	Cyan        = "\033[36m"
	White       = "\033[37m"
	BlueBold    = "\033[34;1m"
	MagentaBold = "\033[35;1m"
	RedBold     = "\033[31;1m"
	YellowBold  = "\033[33;1m"
)

// LogLevel log level
type LogLevel int

const (
	// Silent silent log level
	Silent LogLevel = iota + 1
	// Error error log level
	Error
	// Warn warn log level
	Warn
	// Info info log level
	Info
)

// Writer log writer interface
type Writer interface {
	Printf(string, ...interface{})
}

// Config logger config
type Config struct {
	SlowThreshold             time.Duration
	Colorful                  bool
	IgnoreRecordNotFoundError bool
	ParameterizedQueries      bool
	LogLevel                  LogLevel
}

// Interface logger interface
type Interface interface {
	LogMode(LogLevel) Interface
	Info(context.Context, string, ...interface{})
	Warn(context.Context, string, ...interface{})
	Error(context.Context, string, ...interface{})
	Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}

var (
	// Discard Discard logger will print any log to io.Discard
	Discard = New(log.New(io.Discard, "", log.LstdFlags), Config{})
	// Default Default logger
	Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{
		SlowThreshold:             200 * time.Millisecond,
		LogLevel:                  Warn,
		IgnoreRecordNotFoundError: false,
		Colorful:                  true,
	})
	// Recorder Recorder logger records running SQL into a recorder instance
	Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
)

// New initialize logger
func ( Writer,  Config) Interface {
	var (
		      = "%s\n[info] "
		      = "%s\n[warn] "
		       = "%s\n[error] "
		     = "%s\n[%.3fms] [rows:%v] %s"
		 = "%s %s\n[%.3fms] [rows:%v] %s"
		  = "%s %s\n[%.3fms] [rows:%v] %s"
	)

	if .Colorful {
		 = Green + "%s\n" + Reset + Green + "[info] " + Reset
		 = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
		 = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
		 = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
		 = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
		 = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
	}

	return &logger{
		Writer:       ,
		Config:       ,
		infoStr:      ,
		warnStr:      ,
		errStr:       ,
		traceStr:     ,
		traceWarnStr: ,
		traceErrStr:  ,
	}
}

type logger struct {
	Writer
	Config
	infoStr, warnStr, errStr            string
	traceStr, traceErrStr, traceWarnStr string
}

// LogMode log mode
func ( *logger) ( LogLevel) Interface {
	 := *
	.LogLevel = 
	return &
}

// Info print info
func ( logger) ( context.Context,  string,  ...interface{}) {
	if .LogLevel >= Info {
		.Printf(.infoStr+, append([]interface{}{utils.FileWithLineNum()}, ...)...)
	}
}

// Warn print warn messages
func ( logger) ( context.Context,  string,  ...interface{}) {
	if .LogLevel >= Warn {
		.Printf(.warnStr+, append([]interface{}{utils.FileWithLineNum()}, ...)...)
	}
}

// Error print error messages
func ( logger) ( context.Context,  string,  ...interface{}) {
	if .LogLevel >= Error {
		.Printf(.errStr+, append([]interface{}{utils.FileWithLineNum()}, ...)...)
	}
}

// Trace print sql message
func ( logger) ( context.Context,  time.Time,  func() (string, int64),  error) {
	if .LogLevel <= Silent {
		return
	}

	 := time.Since()
	switch {
	case  != nil && .LogLevel >= Error && (!errors.Is(, ErrRecordNotFound) || !.IgnoreRecordNotFoundError):
		,  := ()
		if  == -1 {
			.Printf(.traceErrStr, utils.FileWithLineNum(), , float64(.Nanoseconds())/1e6, "-", )
		} else {
			.Printf(.traceErrStr, utils.FileWithLineNum(), , float64(.Nanoseconds())/1e6, , )
		}
	case  > .SlowThreshold && .SlowThreshold != 0 && .LogLevel >= Warn:
		,  := ()
		 := fmt.Sprintf("SLOW SQL >= %v", .SlowThreshold)
		if  == -1 {
			.Printf(.traceWarnStr, utils.FileWithLineNum(), , float64(.Nanoseconds())/1e6, "-", )
		} else {
			.Printf(.traceWarnStr, utils.FileWithLineNum(), , float64(.Nanoseconds())/1e6, , )
		}
	case .LogLevel == Info:
		,  := ()
		if  == -1 {
			.Printf(.traceStr, utils.FileWithLineNum(), float64(.Nanoseconds())/1e6, "-", )
		} else {
			.Printf(.traceStr, utils.FileWithLineNum(), float64(.Nanoseconds())/1e6, , )
		}
	}
}

// Trace print sql message
func ( logger) ( context.Context,  string,  ...interface{}) (string, []interface{}) {
	if .Config.ParameterizedQueries {
		return , nil
	}
	return , 
}

type traceRecorder struct {
	Interface
	BeginAt      time.Time
	SQL          string
	RowsAffected int64
	Err          error
}

// New new trace recorder
func ( traceRecorder) () *traceRecorder {
	return &traceRecorder{Interface: .Interface, BeginAt: time.Now()}
}

// Trace implement logger interface
func ( *traceRecorder) ( context.Context,  time.Time,  func() (string, int64),  error) {
	.BeginAt = 
	.SQL, .RowsAffected = ()
	.Err = 
}