package log

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/fatih/color"
)

// 日志级别
type Level int

const (
	DebugLevel Level = iota
	InfoLevel
	WarnLevel
	ErrorLevel
	FatalLevel
)

// 级别名称
var levelNames = map[Level]string{
	DebugLevel: "DEBUG",
	InfoLevel:  "INFO",
	WarnLevel:  "WARN",
	ErrorLevel: "ERROR",
	FatalLevel: "FATAL",
}

// 级别简写
var levelShort = map[Level]string{
	DebugLevel: "[d]",
	InfoLevel:  "[i]",
	WarnLevel:  "[w]",
	ErrorLevel: "[e]",
	FatalLevel: "[f]",
}

// 级别颜色
var levelColor = map[Level]func(format string, a ...interface{}) string{
	DebugLevel: color.CyanString,    // 青色
	InfoLevel:  color.GreenString,   // 绿色
	WarnLevel:  color.YellowString,  // 黄色
	ErrorLevel: color.RedString,     // 红色
	FatalLevel: color.MagentaString, // 品红
}

// Logger 日志器结构体
type Logger struct {
	mu         sync.Mutex
	consoleOut io.Writer // 控制台输出
	fileOut    io.Writer // 文件输出
	minLevel   Level     // 最小输出级别
	showColor  bool      // 是否显示颜色
	showCaller bool      // 是否显示调用者信息
	callerSkip int       // 调用者跳过的层级
	timeFormat string    // 时间格式
}

// 默认日志器实例
var defaultLogger *Logger

const (
	defaultTimeFormat = "2006-01-02 15:04:05"
	logFile           = "/var/log/sunhpc/sunhpc.log"
)

// Init 初始化日志系统
func Init(verbose bool) {
	// 确保日志目录存在
	if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil {
		fmt.Fprintf(os.Stderr, "创建日志目录失败: %v\n", err)
		os.Exit(1)
	}

	// 打开日志文件
	file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		fmt.Fprintf(os.Stderr, "打开日志文件失败: %v\n", err)
		os.Exit(1)
	}

	// 控制台输出
	consoleOut := os.Stdout

	// 创建日志器
	defaultLogger = &Logger{
		consoleOut: consoleOut,
		fileOut:    file,
		minLevel:   InfoLevel,
		showColor:  true,
		showCaller: false,
		callerSkip: 2,
		timeFormat: defaultTimeFormat,
	}

	// 详细模式下显示调试信息
	if verbose {
		defaultLogger.minLevel = DebugLevel
		defaultLogger.showCaller = true
	}

	// 初始化颜色支持
	if runtime.GOOS == "windows" {
		color.NoColor = false
	}
}

// log 核心日志输出方法
func (l *Logger) log(level Level, format string, args ...interface{}) {
	if level < l.minLevel {
		return
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	// 生成时间戳
	timestamp := time.Now().Format(l.timeFormat)

	// 获取调用者信息
	caller := ""
	if l.showCaller {
		_, file, line, ok := runtime.Caller(l.callerSkip)
		if ok {
			// 只保留文件名和行号
			file = filepath.Base(file)
			caller = fmt.Sprintf(" %s:%d", file, line)
		}
	}

	// 格式化消息
	var message string
	if format == "" {
		message = fmt.Sprint(args...)
	} else {
		message = fmt.Sprintf(format, args...)
	}

	// ---- 控制台输出（带颜色和简写）----
	if l.consoleOut != nil {
		// 获取级别简写
		shortPrefix := levelShort[level]

		// 构建控制台行
		var consoleLine string

		if l.showColor {
			// 带颜色输出 - 简写有颜色，时间戳灰色
			colorFunc := levelColor[level]
			consoleLine = fmt.Sprintf("%s %s %s",
				color.HiBlackString(timestamp), // 时间戳灰色
				colorFunc(shortPrefix),         // 级别简写彩色
				message)                        // 消息普通颜色
		} else {
			// 不带颜色输出
			consoleLine = fmt.Sprintf("%s %s %s",
				timestamp,
				shortPrefix,
				message)
		}

		// 添加调用者信息（灰色）
		if caller != "" {
			if l.showColor {
				consoleLine += fmt.Sprintf(" %s", color.HiBlackString(caller))
			} else {
				consoleLine += fmt.Sprintf(" %s", caller)
			}
		}

		fmt.Fprintln(l.consoleOut, consoleLine)
	}

	// ---- 文件输出（完整格式）----
	if l.fileOut != nil {
		// 获取级别全名
		levelName := levelNames[level]

		// 文件使用完整格式：时间 [级别] 消息 调用者
		fileLine := fmt.Sprintf("%s [%s] %s%s\n",
			timestamp,
			levelName,
			message,
			caller)

		fmt.Fprint(l.fileOut, fileLine)
	}

	// 致命错误退出程序
	if level == FatalLevel {
		os.Exit(1)
	}
}

// 全局日志函数

// Debug 调试日志
func Debug(args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(DebugLevel, "", args...)
	}
}

// Debugf 格式化调试日志
func Debugf(format string, args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(DebugLevel, format, args...)
	}
}

// Info 信息日志
func Info(args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(InfoLevel, "", args...)
	}
}

// Infof 格式化信息日志
func Infof(format string, args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(InfoLevel, format, args...)
	}
}

// Warn 警告日志
func Warn(args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(WarnLevel, "", args...)
	}
}

// Warnf 格式化警告日志
func Warnf(format string, args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(WarnLevel, format, args...)
	}
}

// Error 错误日志
func Error(args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(ErrorLevel, "", args...)
	}
}

// Errorf 格式化错误日志
func Errorf(format string, args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(ErrorLevel, format, args...)
	}
}

// Fatal 致命错误日志，输出后退出程序
func Fatal(args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(FatalLevel, "", args...)
	}
}

// Fatalf 格式化致命错误日志，输出后退出程序
func Fatalf(format string, args ...interface{}) {
	if defaultLogger != nil {
		defaultLogger.log(FatalLevel, format, args...)
	}
}

// Writer 返回一个 io.Writer，可将子命令的输出写入日志（Debug级别）
func Writer() *io.PipeWriter {
	r, w := io.Pipe()
	go func() {
		buf := make([]byte, 1024)
		for {
			n, err := r.Read(buf)
			if n > 0 {
				Debug(string(buf[:n]))
			}
			if err != nil {
				break
			}
		}
	}()
	return w
}

// SetLevel 设置日志级别
func SetLevel(level Level) {
	if defaultLogger != nil {
		defaultLogger.mu.Lock()
		defer defaultLogger.mu.Unlock()
		defaultLogger.minLevel = level
	}
}

// EnableColor 启用/禁用颜色输出
func EnableColor(enable bool) {
	if defaultLogger != nil {
		defaultLogger.mu.Lock()
		defer defaultLogger.mu.Unlock()
		defaultLogger.showColor = enable
	}
}

// EnableCaller 启用/禁用调用者信息
func EnableCaller(enable bool) {
	if defaultLogger != nil {
		defaultLogger.mu.Lock()
		defer defaultLogger.mu.Unlock()
		defaultLogger.showCaller = enable
	}
}

// SetTimeFormat 设置时间格式
func SetTimeFormat(format string) {
	if defaultLogger != nil {
		defaultLogger.mu.Lock()
		defer defaultLogger.mu.Unlock()
		defaultLogger.timeFormat = format
	}
}

// Sync 同步日志文件
func Sync() {
	if defaultLogger != nil && defaultLogger.fileOut != nil {
		if f, ok := defaultLogger.fileOut.(*os.File); ok {
			f.Sync()
		}
	}
}

// Close 关闭日志文件
func Close() error {
	if defaultLogger != nil && defaultLogger.fileOut != nil {
		if f, ok := defaultLogger.fileOut.(*os.File); ok {
			return f.Close()
		}
	}
	return nil
}
