package logs

import (
	"go.uber.org/zap/buffer"
	"go.uber.org/zap/zapcore"
)

// traceKey 是日志中用于调用链的字段名，必须与 GetLogger 中使用的保持一致。
const traceKey = "Trace"

// coloredConsoleEncoder 是一个自定义的 zapcore.Encoder，它实现了两个核心功能：
// 1. 为控制台输出的日志行根据级别添加 ANSI 颜色。
// 2. 确保代表“调用链”的结构化字段总是出现在日志行的末尾。
type coloredConsoleEncoder struct {
	zapcore.Encoder // 嵌入一个标准的 ConsoleEncoder，复用其大部分能力。
}

// NewColoredConsoleEncoder 创建一个新的 coloredConsoleEncoder 实例。
func NewColoredConsoleEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder {
	return &coloredConsoleEncoder{
		Encoder: zapcore.NewConsoleEncoder(cfg),
	}
}

// EncodeEntry 重写了核心的编码方法。
// EncodeEntry 重写了核心的编码方法。
func (c *coloredConsoleEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
	// 1. 直接使用内嵌的 Encoder 编码日志条目和所有字段。
	line, err := c.Encoder.EncodeEntry(entry, fields)
	if err != nil {
		return nil, err
	}

	// 2. 为最终的日志行添加颜色。
	var color string
	switch entry.Level {
	case zapcore.DebugLevel:
		color = blue
	case zapcore.InfoLevel:
		color = green
	case zapcore.WarnLevel:
		color = yellow
	case zapcore.ErrorLevel:
		color = red
	case zapcore.DPanicLevel, zapcore.PanicLevel, zapcore.FatalLevel:
		color = bold + red
	default:
		color = reset
	}

	// 3. 创建一个新的 buffer，将颜色、日志内容和重置代码包裹起来。
	finalBuf := buffer.NewPool().Get()
	finalBuf.AppendString(color)
	finalBuf.Write(line.Bytes())
	finalBuf.AppendString(reset)

	// 4. 如果原始日志行末尾没有换行符，则添加一个。
	if line.Len() > 0 && line.Bytes()[line.Len()-1] != '\n' {
		finalBuf.AppendByte('\n')
	}

	line.Free() // 释放由 c.Encoder.EncodeEntry 创建的 buffer

	return finalBuf, nil
}

// Clone 必须被重写，以确保克隆时返回的是我们自定义的 encoder 类型。
func (c *coloredConsoleEncoder) Clone() zapcore.Encoder {
	// 克隆内嵌的 Encoder，并用它来创建一个新的 coloredConsoleEncoder
	return &coloredConsoleEncoder{
		Encoder: c.Encoder.Clone(),
	}
}
