package logger

import (
	"encoding/json"
	stringUtils "eta/eta_mini_ht_api/common/utils/string"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"github.com/beego/beego/v2/server/web/context"
	"log"
	"os"
	"path"
	"strings"
	"sync"
)

const (
	DefalutLogFilePath = "./etalogs"
	LogChannelLen      = 10000
)

var (
	loggerHandler *CustomLogger
	logMutex      = &sync.Mutex{}
)

type logger struct {
	*logs.BeeLogger
	filter Filter
}

type CustomLogger struct {
	logs []*logger
}

// Logger interface
type Logger interface {
	Info(msg string, v ...interface{})
	Warn(msg string, v ...interface{})
	Error(msg string, v ...interface{})
}

func Info(msg string, v ...interface{}) {
	logMutex.Lock()
	defer logMutex.Unlock()
	loggerHandler.Info(msg, v...)
}

func Error(msg string, v ...interface{}) {
	logMutex.Lock()
	defer logMutex.Unlock()
	loggerHandler.Error(msg, v...)
}

func Warn(msg string, v ...interface{}) {
	logMutex.Lock()
	defer logMutex.Unlock()
	loggerHandler.Warn(msg, v...)
}
func Debug(msg string, v ...interface{}) {
	loggerHandler.Debug(msg, v...)
}

func InfoWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
	if traceId := ctx.Input.GetData("traceId"); traceId != "" {
		msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
	}
	Info(msg, v...)
}

func ErrorWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
	if traceId := ctx.Input.GetData("traceId"); traceId != "" {
		msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
	}
	Error(msg, v...)
}

func WarnWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
	if traceId := ctx.Input.GetData("traceId"); traceId != "" {
		msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
	}
	Warn(msg, v...)
}
func DebugWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
	if traceId := ctx.Input.GetData("traceId"); traceId != "" {
		msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
	}
	Debug(msg, v...)
}
func (c *CustomLogger) Debug(msg string, v ...interface{}) {
	for _, cusLogger := range c.logs {
		if cusLogger.GetLevel() >= logs.LevelDebug && cusLogger.filter.ShouldLog(msg) {
			cusLogger.Debug(msg, v...)
		}

	}
}
func (c *CustomLogger) Info(msg string, v ...interface{}) {
	for _, cusLogger := range c.logs {
		if cusLogger.GetLevel() >= logs.LevelInfo && cusLogger.filter.ShouldLog(msg) {
			cusLogger.Info(msg, v...)
		}

	}
}

func (c *CustomLogger) Error(msg string, v ...interface{}) {
	for _, cusLogger := range c.logs {
		if cusLogger.GetLevel() >= logs.LevelError && cusLogger.filter.ShouldLog(msg) {
			cusLogger.Error(msg, v...)
		}
	}
}

func (c *CustomLogger) Warn(msg string, v ...interface{}) {
	for _, cusLogger := range c.logs {
		if cusLogger.GetLevel() >= logs.LevelWarning && cusLogger.filter.ShouldLog(msg) {
			cusLogger.Warn(msg, v...)
		}
	}
}

func init() {
	var logCfg logConfig
	configFile, err := os.ReadFile("conf/log/log_config.json")
	if err != nil {
		log.Fatalf("Failed to read log config: %v", err)
	}
	err = json.Unmarshal(configFile, &logCfg)
	if err != nil {
		log.Fatalf("Failed to parse log config: %v", err)
	}
	initLogger(logCfg)
}

var levelTrans = map[string]int{
	"emergency": logs.LevelEmergency,
	"alert":     logs.LevelAlert,
	"critical":  logs.LevelCritical,
	"error":     logs.LevelError,
	"warn":      logs.LevelWarning,
	"notice":    logs.LevelNotice,
	"info":      logs.LevelInformational,
	"debug":     logs.LevelDebug,
}

var terminalType = map[string]string{
	"console": logs.AdapterConsole,
	"file":    logs.AdapterFile,
}

func GetInstance() Logger {
	return loggerHandler
}
func initLogger(logCfg logConfig) {
	if loggerHandler == nil {
		loggerHandler = new(CustomLogger)
	}
	if stringUtils.IsEmptyOrNil(logCfg.FilePath) {
		logCfg.FilePath = DefalutLogFilePath
	}
	for _, appenderItem := range logCfg.Appenders {
		terminal, ok := terminalType[appenderItem.Type]
		if !ok {
			fmt.Println("初始化日志执行器失败:{%s},终端类型不支持{type:%s}", appenderItem.FileName, appenderItem.Type)
			continue
		}
		var beeLogger *logs.BeeLogger
		if terminal == logs.AdapterConsole {
			beeLogger = logs.NewLogger(LogChannelLen)
			err := beeLogger.SetLogger(logs.AdapterConsole)
			if err != nil {
				fmt.Println("创建日志执行器失败:{%s} %v", appenderItem.FileName, err)
				continue
			}
		} else {
			logFile := appenderItem.FileName
			os.MkdirAll(logCfg.FilePath, os.ModePerm)
			// 打开文件
			appenderItem.FileName = path.Join(logCfg.FilePath, logFile)
			props, err := convertAppenderToLog(&appenderItem)
			if err != nil {
				fmt.Println("初始化日志执行器失败:{%s} %v", appenderItem.FileName, err)
				continue
			}
			b, _ := json.Marshal(props)
			beeLogger = logs.NewLogger(LogChannelLen)
			err = beeLogger.SetLogger(logs.AdapterFile, string(b))
			if err != nil {
				fmt.Println("设置日志执行器失败:{%s} %v", appenderItem.FileName, err)
				continue
			}
			beeLogger.EnableFuncCallDepth(true)
		}
		loggerHandler.logs = append(loggerHandler.logs, &logger{BeeLogger: beeLogger,
			filter: NewLevelFilter(appenderItem.Filter)})
	}
}

// ConvertAppenderToLog 将 appender 结构体转换为 log 结构体
func convertAppenderToLog(a *appender) (*logProps, error) {
	lvl, ok := levelTrans[a.Level]
	if !ok {
		return nil, fmt.Errorf("unknown log level: %s", a.Level)
	}

	return &logProps{
		Prefix:   a.Prefix,
		FileName: a.FileName,
		MaxLines: a.MaxLines,
		MaxSize:  a.MaxSize,
		Daily:    a.Daily,
		MaxDays:  a.MaxDays,
		Rotate:   a.Rotate,
		Level:    lvl,
		Color:    a.Color,
	}, nil
}

// Filter 接口定义
type Filter interface {
	ShouldLog(message string) bool
}

// LevelFilter 实现 Filter 接口,根据日志级别过滤日志
type ContentFilter struct {
	filterStr string
}

// NewLevelFilter 创建一个新的 LevelFilter 实例
func NewLevelFilter(filterStr string) *ContentFilter {
	return &ContentFilter{filterStr: filterStr}
}

// ShouldLog 根据日志级别决定是否记录日志
func (lf *ContentFilter) ShouldLog(message string) bool {
	return strings.Contains(message, lf.filterStr)
}

// logConfig 日志配置
type logConfig struct {
	FilePath  string     `json:"filepath" description:"日志路径"`
	Appenders []appender `json:"appenders" description:"日志记录"`
}

// appender beeLogger JSON配置
type appender struct {
	Filter   string `json:"filter"`
	Prefix   string `json:"perfix" description:"日志前缀"`
	Type     string `json:"type" description:"终端类型"`
	FileName string `json:"filename" description:"保存的文件名"`
	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
	Level    string `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
	Color    bool   `json:"color" description:"日志是否输出颜色"`
}

// logProps beeLogger 配置
type logProps struct {
	Prefix   string `json:"perfix" description:"日志前缀"`
	FileName string `json:"filename" description:"保存的文件名"`
	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
	Level    int    `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
	Color    bool   `json:"color" description:"日志是否输出颜色"`
}