package log

import (
	"fmt"

	"github.com/rs/zerolog"
	nfs "github.com/willscott/go-nfs"
)

var _ nfs.Logger = (*NFSLog)(nil)

type NFSLog struct {
	r zerolog.Logger
	l zerolog.Logger
}

func NewNFSLog(r zerolog.Logger) nfs.Logger {
	return &NFSLog{
		r: r,
		l: r.Level(zerolog.DebugLevel),
	}
}

// Debug implements nfs.Logger.
func (l *NFSLog) Debug(args ...interface{}) {
	l.l.Debug().Msg(fmt.Sprint(args...))
}

// Debugf implements nfs.Logger.
func (l *NFSLog) Debugf(format string, args ...interface{}) {
	l.l.Debug().Msgf(format, args...)
}

// Error implements nfs.Logger.
func (l *NFSLog) Error(args ...interface{}) {
	l.l.Error().Msg(fmt.Sprint(args...))
}

// Errorf implements nfs.Logger.
func (l *NFSLog) Errorf(format string, args ...interface{}) {
	l.l.Error().Msgf(format, args...)
}

// Fatal implements nfs.Logger.
func (l *NFSLog) Fatal(args ...interface{}) {
	l.l.Fatal().Msg(fmt.Sprint(args...))
}

// Fatalf implements nfs.Logger.
func (l *NFSLog) Fatalf(format string, args ...interface{}) {
	l.l.Fatal().Msgf(format, args...)
}

// Info implements nfs.Logger.
func (l *NFSLog) Info(args ...interface{}) {
	l.l.Info().Msg(fmt.Sprint(args...))
}

// Infof implements nfs.Logger.
func (l *NFSLog) Infof(format string, args ...interface{}) {
	l.l.Info().Msgf(format, args...)
}

// Panic implements nfs.Logger.
func (l *NFSLog) Panic(args ...interface{}) {
	l.l.Panic().Msg(fmt.Sprint(args...))
}

// Panicf implements nfs.Logger.
func (l *NFSLog) Panicf(format string, args ...interface{}) {
	l.l.Panic().Msgf(format, args...)
}

// Print implements nfs.Logger.
func (l *NFSLog) Print(args ...interface{}) {
	l.l.Print(args...)
}

// Printf implements nfs.Logger.
func (l *NFSLog) Printf(format string, args ...interface{}) {
	l.l.Printf(format, args...)
}

// Trace implements nfs.Logger.
func (l *NFSLog) Trace(args ...interface{}) {
	l.l.Trace().Msg(fmt.Sprint(args...))
}

// Tracef implements nfs.Logger.
func (l *NFSLog) Tracef(format string, args ...interface{}) {
	l.l.Trace().Msgf(format, args...)
}

// Warn implements nfs.Logger.
func (l *NFSLog) Warn(args ...interface{}) {
	l.l.Warn().Msg(fmt.Sprint(args...))
}

// Warnf implements nfs.Logger.
func (l *NFSLog) Warnf(format string, args ...interface{}) {
	l.l.Warn().Msgf(format, args...)
}

// GetLevel implements nfs.Logger.
func (l *NFSLog) GetLevel() nfs.LogLevel {
	zl := l.l.GetLevel()
	switch zl {
	case zerolog.PanicLevel, zerolog.Disabled:
		return nfs.PanicLevel
	case zerolog.FatalLevel:
		return nfs.FatalLevel
	case zerolog.ErrorLevel:
		return nfs.ErrorLevel
	case zerolog.WarnLevel:
		return nfs.WarnLevel
	case zerolog.InfoLevel:
		return nfs.InfoLevel
	case zerolog.DebugLevel:
		return nfs.DebugLevel
	case zerolog.TraceLevel:
		return nfs.TraceLevel
	}
	return nfs.DebugLevel
}

// ParseLevel implements nfs.Logger.
func (l *NFSLog) ParseLevel(level string) (nfs.LogLevel, error) {
	switch level {
	case "panic":
		return nfs.PanicLevel, nil
	case "fatal":
		return nfs.FatalLevel, nil
	case "error":
		return nfs.ErrorLevel, nil
	case "warn":
		return nfs.WarnLevel, nil
	case "info":
		return nfs.InfoLevel, nil
	case "debug":
		return nfs.DebugLevel, nil
	case "trace":
		return nfs.TraceLevel, nil
	}
	var ll nfs.LogLevel
	return ll, fmt.Errorf("invalid log level %q", level)
}

// SetLevel implements nfs.Logger.
func (l *NFSLog) SetLevel(level nfs.LogLevel) {
	switch level {
	case nfs.PanicLevel:
		l.l = l.r.Level(zerolog.PanicLevel)
		return
	case nfs.FatalLevel:
		l.l = l.r.Level(zerolog.FatalLevel)
		return
	case nfs.ErrorLevel:
		l.l = l.r.Level(zerolog.ErrorLevel)
		return
	case nfs.WarnLevel:
		l.l = l.r.Level(zerolog.WarnLevel)
		return
	case nfs.InfoLevel:
		l.l = l.r.Level(zerolog.InfoLevel)
		return
	case nfs.DebugLevel:
		l.l = l.r.Level(zerolog.DebugLevel)
		return
	case nfs.TraceLevel:
		l.l = l.r.Level(zerolog.TraceLevel)
		return
	}
}