package log

import (
	"fmt"
	"os"
)

type LevelLogger struct {
	Level  uint8
	Logger Logger
}

func (d *LevelLogger) Error(f string, v ...any) {
	if d.Level < LevelError {
		return
	}
	d.Logger.Error(f, v...)
}

func (d *LevelLogger) Warn(f string, v ...any) {
	if d.Level < LevelWarn {
		return
	}
	d.Logger.Warn(f, v...)
}

func (d *LevelLogger) Info(f string, v ...any) {
	if d.Level < LevelInfo {
		return
	}
	d.Logger.Info(f, v...)
}

func (d *LevelLogger) Debug(f string, v ...any) {
	if d.Level < LevelDebug {
		return
	}
	d.Logger.Debug(f, v...)
}

func (d *LevelLogger) CallDepthPlus() {
	d.Logger.CallDepthPlus()
}

func (d *LevelLogger) CallDepthMinus() {
	d.Logger.CallDepthMinus()
}

func NewLevelLogger(level uint8, logger Logger) *LevelLogger {
	return &LevelLogger{Level: level, Logger: logger}
}

type MultiLogger []Logger

func (l MultiLogger) Error(f string, v ...any) {
	for _, logger := range l {
		logger.Error(f, v...)
	}
}

func (l MultiLogger) Warn(f string, v ...any) {
	for _, logger := range l {
		logger.Warn(f, v...)
	}
}

func (l MultiLogger) Info(f string, v ...any) {
	for _, logger := range l {
		logger.Info(f, v...)
	}
}

func (l MultiLogger) Debug(f string, v ...any) {
	for _, logger := range l {
		logger.Debug(f, v...)
	}
}

func (l MultiLogger) CallDepthPlus() {
	for _, logger := range l {
		logger.CallDepthPlus()
	}
}

func (l MultiLogger) CallDepthMinus() {
	for _, logger := range l {
		logger.CallDepthMinus()
	}
}

// ErrorLogger 实现 Logger 接口, 但仅调用 Warn 与 Error 时会有效
type ErrorLogger struct {
	Logger Logger
}

func (e *ErrorLogger) Error(f string, v ...any) {
	e.Logger.CallDepthPlus()
	e.Logger.Error(f, v...)
	e.Logger.CallDepthMinus()
}

func (e *ErrorLogger) Warn(f string, v ...any) {
	e.Logger.CallDepthPlus()
	e.Logger.Warn(f, v...)
	e.Logger.CallDepthMinus()
}

func (e *ErrorLogger) Info(_ string, _ ...any)  {}
func (e *ErrorLogger) Debug(_ string, _ ...any) {}

func (e *ErrorLogger) CallDepthPlus() {
	e.Logger.CallDepthPlus()
}

func (e *ErrorLogger) CallDepthMinus() {
	e.Logger.CallDepthMinus()
}

var (
	// gLog are global default LevelLogger
	gLog = MultiLogger{NewLevelLogger(LevelDebug, NewLogger(3, os.Stdout))}
)

// SetLevel
// Deprecated, remove after later
func SetLevel(level uint8) {
	for _, logger := range gLog {
		if lg, ok := logger.(*LevelLogger); ok {
			lg.Level = level
		}
	}
}

func SetServerMod(address string) {
	client, err := NewClientLogger(address)
	if err != nil {
		panic(err)
	}
	gLog = MultiLogger{client}
}

func SetOutput(logger ...Logger) {
	gLog = logger
}

func Default() Logger {
	return gLog
}

func Debug(f string, v ...any) {
	gLog.Debug(f, v...)
}

func Info(f string, v ...any) {
	gLog.Info(f, v...)
}

func Warn(f string, v ...any) {
	gLog.Warn(f, v...)
}

func Error(f string, v ...any) {
	gLog.Error(f, v...)
}

func Panic(f string, v ...any) {
	gLog.Error(f, v...)
	panic(fmt.Sprintf(f, v...))
}

func Fatal(f string, v ...any) {
	gLog.Error(f, v...)
	os.Exit(1)
}
