package logger

import (
	"fmt"
	"os"
	"sync"

	"git.listensoft.net/tool/jspkit/config"
	"git.listensoft.net/tool/jspkit/logger/zapx"
	amqp "github.com/rabbitmq/amqp091-go"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

var (
	logger *zap.SugaredLogger // 日志对象
	mqConn *amqp.Connection   // 保存MQ连接
	mu     sync.Mutex         // 用于保护mqConn
)

// InitLogger 初始化日志
func InitLogger(config *config.System) error {
	cfg := config.Logger
	// 设置默认值
	if cfg.MaxSize == 0 {
		cfg.MaxSize = 100
	}
	if cfg.MaxBackups == 0 {
		cfg.MaxBackups = 500
	}
	if cfg.MaxAge == 0 {
		cfg.MaxAge = 28
	}

	// 配置lumberjack
	hook := &lumberjack.Logger{
		Filename:   cfg.Filename,
		MaxSize:    cfg.MaxSize,
		MaxBackups: cfg.MaxBackups,
		MaxAge:     cfg.MaxAge,
		Compress:   cfg.Compress,
	}

	// 设置日志级别
	level := zap.InfoLevel
	if cfg.Level != "" {
		var err error
		level, err = zapcore.ParseLevel(cfg.Level)
		if err != nil {
			return err
		}
	}

	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	cores := []zapcore.Core{}
	if cfg.ToMq {
		dsn := fmt.Sprintf("amqp://%s:%s@%s:%d/", cfg.MqSetting.Username, cfg.MqSetting.Password, cfg.MqSetting.Host, cfg.MqSetting.Port)
		conn, err := amqp.Dial(dsn)
		if err == nil {
			mu.Lock()
			mqConn = conn // 保存连接
			mu.Unlock()

			encoder := zapx.NewEncoder("taxrobot", zapx.CallerTrimmedPath)
			wsc, _ := zapx.NewWriter(conn)

			cores = append(cores, zapcore.NewCore(encoder, wsc, level))
		}
	}
	// 创建Core
	var basecore zapcore.Core
	fileWriter := zapcore.AddSync(hook)
	if cfg.Console {
		// 同时输出到文件和控制台
		consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
		fileEncoder := zapcore.NewJSONEncoder(encoderConfig)
		basecore = zapcore.NewTee(
			zapcore.NewCore(fileEncoder, fileWriter, level),
			zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level),
		)
	} else {
		// 只输出到文件
		fileEncoder := zapcore.NewJSONEncoder(encoderConfig)
		basecore = zapcore.NewCore(fileEncoder, fileWriter, level)
	}
	cores = append(cores, basecore)
	// 创建Logger
	logger = zap.New(zapcore.NewTee(cores...), zap.AddCaller(), zap.AddCallerSkip(1)).Sugar()
	return nil
}

// GetLogger 获取全局 logger
func GetLogger() *zap.Logger {
	// 因为包级别函数的原因，需要调整下 caller skip 后再返回
	return logger.Desugar().WithOptions(zap.AddCallerSkip(-1))
}

// 关于为什么用 [Level]ln 系列方法，见 [TestLogVsLogLn]。

// Debug 输出Debug级别日志
func Debug(args ...any) {
	logger.Debugln(args...)
}

// Info 输出Info级别日志
func Info(args ...any) {
	logger.Infoln(args...)
}

// Warn 输出Warn级别日志
func Warn(args ...any) {
	logger.Warnln(args...)
}

// Error 输出Error级别日志
func Error(args ...any) {
	logger.Errorln(args...)
}

// Fatal 输出Fatal级别日志
func Fatal(args ...any) {
	logger.Fatalln(args...)
}

// Close 关闭日志相关资源，包括MQ连接
func Close() error {
	if logger != nil {
		logger.Sync()
	}

	mu.Lock()
	defer mu.Unlock()

	if mqConn != nil {
		err := mqConn.Close()
		mqConn = nil
		return err
	}
	return nil
}
