package utils

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

// LogLevel 日志级别
type LogLevel int

const (
	DEBUG LogLevel = iota
	INFO
	WARN
	ERROR
	FATAL
)

// String 返回日志级别的字符串表示
func (l LogLevel) String() string {
	switch l {
	case DEBUG:
		return "DEBUG"
	case INFO:
		return "INFO"
	case WARN:
		return "WARN"
	case ERROR:
		return "ERROR"
	case FATAL:
		return "FATAL"
	default:
		return "UNKNOWN"
	}
}

// Logger 统一日志器
type Logger struct {
	debugLogger *log.Logger
	infoLogger  *log.Logger
	warnLogger  *log.Logger
	errorLogger *log.Logger
	fatalLogger *log.Logger

	file   *os.File
	mu     sync.Mutex
	config *LogConfig
}

// LogConfig 日志配置
type LogConfig struct {
	LogDir         string   // 日志目录
	LogLevel       LogLevel // 日志级别
	MaxFileSize    int64    // 单个日志文件最大大小（MB）
	MaxBackups     int      // 最大备份文件数
	MaxAge         int      // 日志文件最大保留天数
	EnableConsole  bool     // 是否启用控制台输出
	EnableFile     bool     // 是否启用文件输出
	EnableRotation bool     // 是否启用日志轮转
}

// DefaultConfig 默认配置
func DefaultConfig() *LogConfig {
	return &LogConfig{
		LogDir:         "logs",
		LogLevel:       INFO,
		MaxFileSize:    100, // 100MB
		MaxBackups:     5,
		MaxAge:         30, // 30天
		EnableConsole:  true,
		EnableFile:     true,
		EnableRotation: true,
	}
}

var (
	globalLogger *Logger
	onceLogger   sync.Once
)

// InitLogger 初始化全局日志器
func InitLogger(config *LogConfig) error {
	var err error
	onceLogger.Do(func() {
		if config == nil {
			config = DefaultConfig()
		}

		globalLogger, err = NewLogger(config)
	})
	return err
}

// GetLogger 获取全局日志器
func GetLogger() *Logger {
	if globalLogger == nil {
		InitLogger(nil)
	}
	return globalLogger
}

// NewLogger 创建新的日志器
func NewLogger(config *LogConfig) (*Logger, error) {
	if config == nil {
		config = DefaultConfig()
	}

	logger := &Logger{
		config: config,
	}

	// 创建日志目录
	if config.EnableFile {
		if err := os.MkdirAll(config.LogDir, 0755); err != nil {
			return nil, fmt.Errorf("创建日志目录失败: %v", err)
		}
	}

	// 初始化日志文件
	if err := logger.initLogFile(); err != nil {
		return nil, err
	}

	// 初始化日志器
	logger.initLoggers()

	// 启动日志轮转检查
	if config.EnableRotation {
		go logger.startRotationCheck()
	}

	return logger, nil
}

// initLogFile 初始化日志文件
func (l *Logger) initLogFile() error {
	if !l.config.EnableFile {
		return nil
	}

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

	// 关闭现有文件
	if l.file != nil {
		l.file.Close()
	}

	// 创建新的日志文件
	logFile := filepath.Join(l.config.LogDir, fmt.Sprintf("app_%s.log", GetCurrentTime().Format("2006-01-02")))
	file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return fmt.Errorf("创建日志文件失败: %v", err)
	}

	l.file = file
	return nil
}

// initLoggers 初始化各个级别的日志器
func (l *Logger) initLoggers() {
	var writers []io.Writer

	// 添加控制台输出
	if l.config.EnableConsole {
		writers = append(writers, os.Stdout)
	}

	// 添加文件输出
	if l.config.EnableFile && l.file != nil {
		writers = append(writers, l.file)
	}

	multiWriter := io.MultiWriter(writers...)

	// 创建各个级别的日志器
	l.debugLogger = log.New(multiWriter, "[DEBUG] ", log.LstdFlags)
	l.infoLogger = log.New(multiWriter, "[INFO] ", log.LstdFlags)
	l.warnLogger = log.New(multiWriter, "[WARN] ", log.LstdFlags)
	l.errorLogger = log.New(multiWriter, "[ERROR] ", log.LstdFlags)
	l.fatalLogger = log.New(multiWriter, "[FATAL] ", log.LstdFlags)
}

// log 内部日志方法
func (l *Logger) log(level LogLevel, format string, args ...interface{}) {
	if level < l.config.LogLevel {
		return
	}

	// 获取调用者信息
	_, file, line, ok := runtime.Caller(2)
	if !ok {
		file = "unknown"
		line = 0
	}

	// 提取文件名
	fileName := filepath.Base(file)

	// 格式化消息
	message := fmt.Sprintf(format, args...)

	// 添加调用位置信息
	fullMessage := fmt.Sprintf("[%s:%d] %s", fileName, line, message)

	switch level {
	case DEBUG:
		l.debugLogger.Println(fullMessage)
	case INFO:
		l.infoLogger.Println(fullMessage)
	case WARN:
		l.warnLogger.Println(fullMessage)
	case ERROR:
		l.errorLogger.Println(fullMessage)
	case FATAL:
		l.fatalLogger.Println(fullMessage)
		os.Exit(1)
	}
}

// Debug 调试日志
func (l *Logger) Debug(format string, args ...interface{}) {
	l.log(DEBUG, format, args...)
}

// Info 信息日志
func (l *Logger) Info(format string, args ...interface{}) {
	l.log(INFO, format, args...)
}

// Warn 警告日志
func (l *Logger) Warn(format string, args ...interface{}) {
	l.log(WARN, format, args...)
}

// Error 错误日志
func (l *Logger) Error(format string, args ...interface{}) {
	l.log(ERROR, format, args...)
}

// Fatal 致命错误日志
func (l *Logger) Fatal(format string, args ...interface{}) {
	l.log(FATAL, format, args...)
}

// startRotationCheck 启动日志轮转检查
func (l *Logger) startRotationCheck() {
	ticker := time.NewTicker(1 * time.Hour) // 每小时检查一次
	defer ticker.Stop()

	for range ticker.C {
		l.checkRotation()
	}
}

// checkRotation 检查是否需要轮转日志
func (l *Logger) checkRotation() {
	if !l.config.EnableFile || l.file == nil {
		return
	}

	// 检查文件大小
	fileInfo, err := l.file.Stat()
	if err != nil {
		return
	}

	// 如果文件超过最大大小，进行轮转
	if fileInfo.Size() > l.config.MaxFileSize*1024*1024 {
		l.rotateLog()
	}

	// 清理旧日志文件
	l.cleanOldLogs()
}

// rotateLog 轮转日志文件
func (l *Logger) rotateLog() {
	l.mu.Lock()
	defer l.mu.Unlock()

	// 关闭当前文件
	if l.file != nil {
		l.file.Close()
	}

	// 重命名当前日志文件
	currentLogFile := filepath.Join(l.config.LogDir, fmt.Sprintf("app_%s.log", GetCurrentTime().Format("2006-01-02")))
	backupLogFile := filepath.Join(l.config.LogDir, fmt.Sprintf("app_%s_%s.log", GetCurrentTime().Format("2006-01-02"), GetCurrentTime().Format("15-04-05")))

	if _, err := os.Stat(currentLogFile); err == nil {
		os.Rename(currentLogFile, backupLogFile)
	}

	// 创建新的日志文件
	l.initLogFile()
	l.initLoggers()
}

// cleanOldLogs 清理旧日志文件
func (l *Logger) cleanOldLogs() {
	if l.config.MaxAge <= 0 {
		return
	}

	files, err := filepath.Glob(filepath.Join(l.config.LogDir, "app_*.log"))
	if err != nil {
		return
	}

	cutoffTime := GetCurrentTime().AddDate(0, 0, -l.config.MaxAge)

	for _, file := range files {
		fileInfo, err := os.Stat(file)
		if err != nil {
			continue
		}

		if fileInfo.ModTime().Before(cutoffTime) {
			os.Remove(file)
		}
	}
}

// Close 关闭日志器
func (l *Logger) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.file != nil {
		return l.file.Close()
	}
	return nil
}

// 全局便捷函数
func Debug(format string, args ...interface{}) {
	GetLogger().Debug(format, args...)
}

func Info(format string, args ...interface{}) {
	GetLogger().Info(format, args...)
}

func Warn(format string, args ...interface{}) {
	GetLogger().Warn(format, args...)
}

func Error(format string, args ...interface{}) {
	GetLogger().Error(format, args...)
}

func Fatal(format string, args ...interface{}) {
	GetLogger().Fatal(format, args...)
}
