package logger

import (
	"errors"
	json "github.com/json-iterator/go"
	"sync"
)

var (
	lock sync.Mutex
	// 全局log接口map
	loggerMap map[string]Log
)

type logger struct {
	module   string
	pid      int
	operator string
	output   []driver // 输出驱动列表
}

// log 接口
type Log interface {
	Debug(content string, extra ...interface{})
	Info(content string, extra ...interface{})
	Warn(content string, extra ...interface{})
	Error(content string, extra ...interface{})
	Fatal(content string, extra ...interface{})
}

// 获取log接口
func NewLogger(operator string, module string) (Log, error) {
	lock.Lock()
	defer lock.Unlock()
	if loggerMap == nil {
		loggerMap = make(map[string]Log)
	}
	if loggerMap[module] != nil {
		return loggerMap[module], nil
	}
	return initLogger(module, operator)
}

// 根据全局配置初始化log接口
func initLogger(module string, operator string) (Log, error) {
	pid := getPid()
	defaultLogger := NewDefaultLogger()
	innerLog := &logger{
		module:   module,
		pid:      pid,
		operator: operator,
		output:   make([]driver, 0),
	}
	// 若没有module配置使用root配置
	config, exist := loggerConfig.Config[module]
	if !exist {
		config = loggerConfig.Config["root"]
	}
	for _, value := range config {
		levelInt := changeToInt(value.Level)
		// 初始化db driver
		if value.DriverType == "db" {
			driverConfig, exist := outputConfig.DB[value.DriverName]
			if !exist {
				continue
			}
			switch driverConfig.DBType {
			case "mongo":
				driver, err := NewMongoDriver(driverConfig, levelInt)
				if err != nil {
					return defaultLogger, err
				}
				innerLog.output = append(innerLog.output, driver)
			}
		} else if value.DriverType == "file" { // 初始话file driver
			driverConfig, exist := outputConfig.File[value.DriverName]
			if !exist {
				continue
			}
			driver, err := NewFileDriver(driverConfig, levelInt)
			if err != nil {
				return defaultLogger, err
			}
			innerLog.output = append(innerLog.output, driver)
		} else if value.DriverType == "console" { // 初始化console driver
			driverConfig := outputConfig.Console
			driver, err := NewConsoleDriver(driverConfig)
			if err != nil {
				return defaultLogger, err
			}
			innerLog.output = append(innerLog.output, driver)
		}
	}
	if len(innerLog.output) == 0 {
		return defaultLogger, errors.New("未获取到日志输出驱动")
	}
	loggerMap[module] = innerLog
	return innerLog, nil
}

func (l *logger) Debug(content string, extra ...interface{}) {
	date := getToday()
	t := getCurrentTime()
	caller := getCaller(2)
	extraStr, err := json.Marshal(extra)
	if err != nil {
		return
	}
	message := message{
		Level:    DebugLevel,
		Module:   l.module,
		Content:  content,
		Date:     date,
		Time:     t,
		Caller:   caller,
		Extra:    string(extraStr),
		Pid:      l.pid,
		Operator: l.operator,
	}
	for _, driver := range l.output {
		driver.Record(message)
	}
}

func (l *logger) Info(content string, extra ...interface{}) {
	date := getToday()
	t := getCurrentTime()
	caller := getCaller(2)
	extraStr, err := json.Marshal(extra)
	if err != nil {
		return
	}
	message := message{
		Level:    infoLevel,
		Module:   l.module,
		Content:  content,
		Date:     date,
		Time:     t,
		Caller:   caller,
		Extra:    string(extraStr),
		Pid:      l.pid,
		Operator: l.operator,
	}
	for _, driver := range l.output {
		driver.Record(message)
	}
}

func (l *logger) Warn(content string, extra ...interface{}) {
	date := getToday()
	t := getCurrentTime()
	caller := getCaller(2)
	extraStr, err := json.Marshal(extra)
	if err != nil {
		return
	}
	message := message{
		Level:    WarnLevel,
		Module:   l.module,
		Content:  content,
		Date:     date,
		Time:     t,
		Caller:   caller,
		Extra:    string(extraStr),
		Pid:      l.pid,
		Operator: l.operator,
	}
	for _, driver := range l.output {
		driver.Record(message)
	}
}

func (l *logger) Error(content string, extra ...interface{}) {
	date := getToday()
	t := getCurrentTime()
	caller := getCaller(2)
	extraStr, err := json.Marshal(extra)
	if err != nil {
		return
	}
	message := message{
		Level:    ErrorLevel,
		Module:   l.module,
		Content:  content,
		Date:     date,
		Time:     t,
		Caller:   caller,
		Extra:    string(extraStr),
		Pid:      l.pid,
		Operator: l.operator,
	}
	for _, driver := range l.output {
		driver.Record(message)
	}
}

func (l *logger) Fatal(content string, extra ...interface{}) {
	date := getToday()
	t := getCurrentTime()
	caller := getCaller(2)
	extraStr, err := json.Marshal(extra)
	if err != nil {
		return
	}
	message := message{
		Level:    FatalLevel,
		Module:   l.module,
		Content:  content,
		Date:     date,
		Time:     t,
		Caller:   caller,
		Extra:    string(extraStr),
		Pid:      l.pid,
		Operator: l.operator,
	}
	for _, driver := range l.output {
		driver.Record(message)
	}
}
