package bootstrap

import (
	"fmt"
	"io"
	"path/filepath"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"

	"designs/config"
	"designs/global"
	"designs/utils"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	// "gopkg.in/natefinch/lumberjack.v2"
	"os"
	"time"
)

var (
	level   zapcore.Level // zap 日志等级
	options []zap.Option  // zap 配置项
)

func InitializeLog() (*zap.SugaredLogger, io.Writer) {
	// 创建根目录
	createRootDir()
	// 设置日志等级
	setLogLevel()

	if config.GetBool("log.showLine") {
		options = append(options, zap.AddCaller())
	}

	writer := getLogWriter() // file-rotatelogs

	// 初始化 zap
	logger := zap.New(getZapCore(writer), options...)
	return logger.Sugar(), writer
}

func createRootDir() {
	if ok, _ := utils.PathExists(config.Get("log.rootDir")); !ok {

		if err := os.Mkdir(config.Get("log.rootDir"), os.ModePerm); err != nil {
			panic(fmt.Errorf("mkdir log root dir failed: %s, %s \n", config.Get("log.rootDir"), err))
		}
	}
}

func setLogLevel() {
	switch config.Get("log.level") {
	case "debug":
		level = zap.DebugLevel
		options = append(options, zap.AddStacktrace(level))
	case "info":
		level = zap.InfoLevel
	case "warn":
		level = zap.WarnLevel
	case "error":
		level = zap.ErrorLevel
		options = append(options, zap.AddStacktrace(level))
	case "dpanic":
		level = zap.DPanicLevel
	case "panic":
		level = zap.PanicLevel
	case "fatal":
		level = zap.FatalLevel
	default:
		level = zap.InfoLevel
	}
}

// 扩展 Zap
func getZapCore(writer io.Writer) zapcore.Core {
	var encoder zapcore.Encoder

	// 调整编码器默认配置
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = func(time time.Time, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString(time.Format("[" + "2006-01-02 15:04:05.000" + "]"))
	}
	encoderConfig.EncodeLevel = func(l zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString(config.Get("app.env") + "." + l.String())
	}

	// 设置编码器
	if config.Get("log.format") == "json" {
		encoder = zapcore.NewJSONEncoder(encoderConfig)
	} else {
		encoder = zapcore.NewConsoleEncoder(encoderConfig)
	}

	syncWriter := zapcore.AddSync(writer)
	return zapcore.NewCore(encoder, syncWriter, level)
}

func getLogWriter() io.Writer {
	logFile := config.Get("log.filename")

	writer, err := rotatelogs.New(
		filepath.Join(global.App.PwdPath, "storage", "logs", logFile),
		rotatelogs.WithMaxAge(-1),
		rotatelogs.WithRotationTime(24*time.Hour),
	)

	if err != nil {
		panic(fmt.Errorf("failed to create rotatelogs: %s", err))
	}

	return writer
}
