// logger/logger.go
package logger

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/sirupsen/logrus"
)

// -------------------------- 1. ANSI 颜色码常量（关键） --------------------------
const (
	// 颜色重置
	ColorReset = "\033[0m"
	// 灰色（日期、文件行号）
	ColorGray = "\033[90m"
	// 日志级别颜色
	ColorDebug = "\033[36m" // 青色 [d]
	ColorInfo  = "\033[32m" // 绿色 [i]
	ColorWarn  = "\033[33m" // 黄色 [w]
	ColorError = "\033[31m" // 红色 [e]
	ColorFatal = "\033[35m" // 紫色 [f]
)

// -------------------------- 1. 定义日志接口 --------------------------
// Logger 日志核心接口，定义所有需要的日志方法
// 所有模块都依赖这个接口，而非具体实现
type Logger interface {
	Debug(args ...interface{})
	Debugf(format string, args ...interface{})
	Info(args ...interface{})
	Infof(format string, args ...interface{})
	Warn(args ...interface{})
	Warnf(format string, args ...interface{})
	Error(args ...interface{})
	Errorf(format string, args ...interface{})
	Fatal(args ...interface{})
	Fatalf(format string, args ...interface{})
}

// -------------------------- 2. 基于logrus的默认实现 --------------------------
// logrusLogger 是 Logger 接口的具体实现（基于logrus）
type logrusLogger struct {
	*logrus.Logger
}

// 实现 Logger 接口的所有方法（直接转发给logrus）
func (l *logrusLogger) Debug(args ...interface{})                 { l.Logger.Debug(args...) }
func (l *logrusLogger) Debugf(format string, args ...interface{}) { l.Logger.Debugf(format, args...) }
func (l *logrusLogger) Info(args ...interface{})                  { l.Logger.Info(args...) }
func (l *logrusLogger) Infof(format string, args ...interface{})  { l.Logger.Infof(format, args...) }
func (l *logrusLogger) Warn(args ...interface{})                  { l.Logger.Warn(args...) }
func (l *logrusLogger) Warnf(format string, args ...interface{})  { l.Logger.Warnf(format, args...) }
func (l *logrusLogger) Error(args ...interface{})                 { l.Logger.Error(args...) }
func (l *logrusLogger) Errorf(format string, args ...interface{}) { l.Logger.Errorf(format, args...) }
func (l *logrusLogger) Fatal(args ...interface{})                 { l.Logger.Fatal(args...) }
func (l *logrusLogger) Fatalf(format string, args ...interface{}) { l.Logger.Fatalf(format, args...) }

// -------------------------- 3. 全局默认实例 + 初始化逻辑 --------------------------
var (
	// DefaultLogger 全局默认日志实例（所有模块可直接用，也可注入自定义实现）
	DefaultLogger Logger
	// once 保证日志只初始化一次
	initOnce sync.Once
)

// LogConfig 日志配置结构体（和项目的config包对齐）
type LogConfig struct {
	Level     string `mapstructure:"level" yaml:"level"`
	Format    string `mapstructure:"format" yaml:"format"`
	Output    string `mapstructure:"output" yaml:"output"`
	Verbose   bool   `mapstructure:"verbose" yaml:"verbose"`
	LogFile   string `mapstructure:"log_file" yaml:"log_file"`
	ShowColor bool   `mapstructure:"show_color" yaml:"show_color"`
}

// 默认配置
var defaultConfig = LogConfig{
	Level:     "info",
	Format:    "text",
	Output:    "stdout",
	Verbose:   false,
	ShowColor: true,
	LogFile:   "/var/log/sunhpc/sunhpc.log",
}

// -------------------------- 5. 自定义Formatter（核心配色逻辑） --------------------------
type CustomFormatter struct {
	ShowColor bool // 是否显示彩色输出
}

// Format 实现 logrus.Formatter 接口，自定义日志格式和颜色
func (f *CustomFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	// 1. 获取日志级别标识和对应颜色
	levelStr, levelColor := getLevelInfo(entry.Level)

	// 2. 获取调用文件和行号（简化路径，只保留文件名+行号）
	file, line := getCallerInfo()
	// 3. 格式化时间（灰色）
	timeStr := entry.Time.Format("2006-01-02 15:04:05")

	// 构建日志行（按你的格式：日期 [级别] 内容  文件:行号）
	var buf bytes.Buffer

	// 颜色开关：如果禁用颜色，所有颜色码置空
	colorReset := ColorReset
	colorGray := ColorGray
	if !f.ShowColor {
		levelColor = ""
		colorGray = ""
		colorReset = ""
	}

	// Debug,打印原始字节,用于调试
	// fmt.Printf("%q\n", entry.Message)

	// 拼接格式：
	// 灰色日期 + 空格 + 带颜色的[级别] + 空格 + 日志内容 + 空格 + 灰色文件行号 + 重置
	fmt.Fprintf(&buf, "%s%s%s %s[%s]%s %s %s%s:%d%s\n",
		colorGray,     // 日期开始灰色
		timeStr,       // 日期字符串
		colorReset,    // 日期结束重置颜色
		levelColor,    // 级别标识颜色
		levelStr,      // 级别标识（i/d/e/w/f）
		colorReset,    // 级别标识结束重置
		entry.Message, // 日志内容（默认色）
		colorGray,     // 文件行号开始灰色
		file,          // 文件名（如db.go）
		line,          // 行号（如64）
		colorReset,    // 文件行号结束重置
	)

	return buf.Bytes(), nil
}

// getLevelInfo 获取日志级别对应的标识和颜色
func getLevelInfo(level logrus.Level) (string, string) {
	switch level {
	case logrus.DebugLevel:
		return "d", ColorDebug
	case logrus.InfoLevel:
		return "i", ColorInfo
	case logrus.WarnLevel:
		return "w", ColorWarn
	case logrus.ErrorLevel:
		return "e", ColorError
	case logrus.FatalLevel:
		return "f", ColorFatal
	default:
		return "i", ColorInfo
	}
}

func getCallerInfo() (string, int) {
	// 从当前调用开始，逐层向上查找
	for i := 2; i < 15; i++ { // i从2开始（跳过getCallerInfo自身）
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}

		// 获取函数名
		funcName := runtime.FuncForPC(pc).Name()

		// 跳过logrus和logger包内部的调用
		if shouldSkipPackage(funcName, file) {
			continue
		}

		// 找到第一个非内部调用的栈帧
		return filepath.Base(file), line
	}

	return "unknown.go", 0
}

// shouldSkipPackage 判断是否需要跳过该调用
func shouldSkipPackage(funcName, file string) bool {
	// 跳过logrus包
	if strings.Contains(funcName, "logrus") ||
		strings.Contains(file, "logrus") {
		return true
	}

	// 跳过logger包（你自己的包装包）
	if strings.Contains(file, "/logger/") {
		return true
	}

	// 跳过runtime包
	if strings.Contains(funcName, "runtime.") {
		return true
	}

	return false
}

// 递归调整调用栈深度（兼容不同场景）
func getCallerInfoWithSkip(skip int) (string, int) {
	_, file, line, ok := runtime.Caller(skip)
	if !ok {
		return "unknown.go", 0
	}
	return filepath.Base(file), line
}

// Init 初始化全局默认日志实例（全局只执行一次）
func Init(cfg LogConfig) {
	initOnce.Do(func() {
		// 1. 创建logrus实例
		logrusInst := logrus.New()

		// 2. 配置输出（控制台 + 文件，可选）
		var outputs []io.Writer
		outputs = append(outputs, os.Stdout) // 控制台输出

		// 如果配置了日志文件，添加文件输出
		if cfg.LogFile != "" {
			// 确保日志目录存在
			dir := filepath.Dir(cfg.LogFile)
			if err := os.MkdirAll(dir, 0755); err != nil {
				// 目录创建失败，只输出警告，不影响程序运行
				logrusInst.Warnf("创建日志目录失败: %v,仅输出到控制台", err)
			} else {
				file, err := os.OpenFile(cfg.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
				if err == nil {
					outputs = append(outputs, file)
				} else {
					logrusInst.Warnf("打开日志文件失败: %v,仅输出到控制台", err)
				}
			}
		}
		logrusInst.SetOutput(io.MultiWriter(outputs...))

		// 3. 配置格式
		logrusInst.SetFormatter(&CustomFormatter{
			ShowColor: cfg.ShowColor,
		})

		// 4. 配置日志级别
		lvl, err := logrus.ParseLevel(cfg.Level)
		if err != nil {
			lvl = logrus.InfoLevel // 解析失败默认Info级别
		}
		// 开启Verbose则强制设为Debug级别
		if cfg.Verbose {
			lvl = logrus.DebugLevel
		}
		logrusInst.SetLevel(lvl)

		// 启用文件行号(必须开启，否则getCallerInfo拿不到数据)
		logrusInst.SetReportCaller(true)

		// 5. 赋值给全局默认实例
		DefaultLogger = &logrusLogger{logrusInst}
	})
}

// -------------------------- 4. 全局快捷调用方法（可选，简化使用） --------------------------
// 如果你不想每次都写 logger.DefaultLogger.Info()，可以封装快捷方法
func Debug(args ...any)                 { DefaultLogger.Debug(args...) }
func Debugf(format string, args ...any) { DefaultLogger.Debugf(format, args...) }
func Info(args ...any)                  { DefaultLogger.Info(args...) }
func Infof(format string, args ...any)  { DefaultLogger.Infof(format, args...) }
func Warn(args ...any)                  { DefaultLogger.Warn(args...) }
func Warnf(format string, args ...any)  { DefaultLogger.Warnf(format, args...) }
func Error(args ...any)                 { DefaultLogger.Error(args...) }
func Errorf(format string, args ...any) { DefaultLogger.Errorf(format, args...) }
func Fatal(args ...any)                 { DefaultLogger.Fatal(args...) }
func Fatalf(format string, args ...any) { DefaultLogger.Fatalf(format, args...) }
