package log

import (
	"fmt"
	"io"
	"os"
)

type defaultLogger struct {
	level   uint8
	client  Logger
	console Logger
	main    Logger
	err     Logger
}

func (d *defaultLogger) Error(f string, v ...any) {
	if d.level < LevelError {
		return
	}
	d.console.Error(f, v...)
	if d.client != nil {
		d.client.Error(f, v...)
	}
	if d.err != nil {
		d.err.Error(f, v...)
	}
	if d.main != nil {
		d.main.Error(f, v...)
	}
}

func (d *defaultLogger) Warn(f string, v ...any) {
	if d.level < LevelWarn {
		return
	}
	d.console.Warn(f, v...)
	if d.client != nil {
		d.client.Warn(f, v...)
	}
	if d.err != nil {
		d.err.Warn(f, v...)
	}
	if d.main != nil {
		d.main.Warn(f, v...)
	}
}

func (d *defaultLogger) Info(f string, v ...any) {
	if d.level < LevelInfo {
		return
	}
	d.console.Info(f, v...)
	if d.client != nil {
		d.client.Info(f, v...)
	}
	if d.main != nil {
		d.main.Info(f, v...)
	}
}

func (d *defaultLogger) Debug(f string, v ...any) {
	if d.level < LevelDebug {
		return
	}
	d.console.Debug(f, v...)
	if d.client != nil {
		d.client.Debug(f, v...)
	}
	if d.main != nil {
		d.main.Debug(f, v...)
	}
}

var (
	dlog = &defaultLogger{
		level: LevelDebug,
	}
)

func init() {
	dlog.console = NewLogger(os.Stdout, 4)
}

func SetLevel(level uint8) {
	dlog.level = level
}

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

func SetOutput(runPath, errPath string) {
	if runPath != "" {
		dlog.main = NewLogger(NewFileWriter("run", runPath), 4)
	}
	if errPath != "" {
		dlog.err = NewLogger(NewFileWriter("err", errPath), 4)
	}
}

func SetConsole(r bool) {
	if r {
		return
	}
	dlog.console = New(io.Discard, "", PrintFlags)
}

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

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

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

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

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

func Fatal(f string, v ...any) {
	dlog.Error(f, v...)
	fmt.Println(fmt.Sprintf(f, v...))
	os.Exit(1)
}
