package log

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const ctxLoggerKey = "zapLogger"

// ServiceType 服务类型
type ServiceType int

const (
	API  ServiceType = iota // API服务
	Task                    // Task服务
)

type Logger struct {
	*zap.Logger
}

// NewLog 创建一个新的日志实例，兼容旧版本配置
func NewLog(conf *viper.Viper) *Logger {
	return NewServiceLog(conf, API)
}

// NewServiceLog 创建特定服务类型的日志实例
func NewServiceLog(conf *viper.Viper, serviceType ServiceType) *Logger {
	var logPath string

	// 从环境变量检查服务类型
	envServiceType := os.Getenv("SERVICE_TYPE")
	if envServiceType == "api" {
		serviceType = API
	} else if envServiceType == "task" {
		serviceType = Task
	}

	// 根据服务类型和日期生成日志文件名
	logFormat := conf.GetString("log.log_format") // 日期格式，如"2006-01-02"
	// 确保有默认的日期格式
	if logFormat == "" {
		logFormat = "2006-01-02"
	}
	currentDate := time.Now().Format(logFormat)

	// 显示调试信息
	fmt.Printf("[日志初始化] 服务类型: %s, 日期: %s\n",
		serviceTypeToString(serviceType), currentDate)

	if serviceType == API && conf.IsSet("log.api_log_file") {
		// 使用API日志路径
		logPath = conf.GetString("log.api_log_file")
		logPath = fmt.Sprintf(logPath, currentDate) // 替换日期占位符
	} else if serviceType == Task && conf.IsSet("log.task_log_file") {
		// 使用Task日志路径
		logPath = conf.GetString("log.task_log_file")
		logPath = fmt.Sprintf(logPath, currentDate) // 替换日期占位符
	} else if conf.IsSet("log.log_file_name") {
		// 即使使用旧配置，也添加日期分区
		logPath = conf.GetString("log.log_file_name")
		// 截取扩展名前的部分，添加日期，然后加上扩展名
		ext := filepath.Ext(logPath)
		base := logPath[:len(logPath)-len(ext)]
		logPath = fmt.Sprintf("%s-%s%s", base, currentDate, ext)
	}

	// 处理相对路径，兼容不同的工作目录
	if strings.HasPrefix(logPath, "./") {
		basePath := "/data/app" // 容器中的日志基础路径
		if _, err := os.Stat(basePath); os.IsNotExist(err) {
			// 如果/data/app不存在，则使用当前目录
			workDir, err := os.Getwd()
			if err == nil {
				basePath = workDir
			} else {
				basePath = "."
			}
		}
		// 将相对路径转换为绝对路径
		logPath = strings.Replace(logPath, "./", basePath+"/", 1)
	}

	// 显示实际使用的日志路径
	fmt.Printf("[日志路径] %s\n", logPath)

	// 确保日志目录存在
	if err := ensureDirExists(logPath); err != nil {
		// 如果创建目录失败，回退到临时目录
		fmt.Printf("Error creating log directory: %v, using default path\n", err)
		logPath = "./logs/app.log"
		ensureDirExists(logPath)
	}

	// 获取日志级别
	lv := conf.GetString("log.log_level")
	var level zapcore.Level
	//debug<info<warn<error<fatal<panic
	switch lv {
	case "debug":
		level = zap.DebugLevel
	case "info":
		level = zap.InfoLevel
	case "warn":
		level = zap.WarnLevel
	case "error":
		level = zap.ErrorLevel
	default:
		level = zap.InfoLevel
	}

	// 日志轮转配置 - 使用DateRotator代替lumberjack.Logger
	hook := NewDateRotator(
		logPath,
		conf.GetInt("log.max_size"),    // 每个日志文件的最大大小单位：M
		conf.GetInt("log.max_backups"), // 日志文件最多保存的备份数
		conf.GetInt("log.max_age"),     // 文件最多保存的天数
		conf.GetBool("log.compress"),   // 是否压缩
		logFormat,                      // 使用相同的日期格式
	)

	// 配置日志编码器
	var encoder zapcore.Encoder
	if conf.GetString("log.encoding") == "console" {
		encoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
			TimeKey:        "ts",
			LevelKey:       "level",
			NameKey:        "Logger",
			CallerKey:      "caller",
			MessageKey:     "msg",
			StacktraceKey:  "stacktrace",
			LineEnding:     zapcore.DefaultLineEnding,
			EncodeLevel:    zapcore.LowercaseColorLevelEncoder,
			EncodeTime:     timeEncoder,
			EncodeDuration: zapcore.SecondsDurationEncoder,
			EncodeCaller:   zapcore.FullCallerEncoder,
		})
	} else {
		encoder = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
			TimeKey:        "time",
			LevelKey:       "level",
			NameKey:        "logger",
			CallerKey:      "caller",
			FunctionKey:    zapcore.OmitKey,
			MessageKey:     "msg",
			StacktraceKey:  "stacktrace",
			LineEnding:     zapcore.DefaultLineEnding,
			EncodeLevel:    zapcore.LowercaseLevelEncoder,
			EncodeTime:     timeEncoder, // 使用自定义时间格式
			EncodeDuration: zapcore.StringDurationEncoder,
			EncodeCaller:   zapcore.ShortCallerEncoder,
		})
	}

	// 创建日志核心
	logOutput := zapcore.NewMultiWriteSyncer(
		zapcore.AddSync(os.Stdout), // 同时输出到控制台
		zapcore.AddSync(hook),      // 和文件
	)
	core := zapcore.NewCore(encoder, logOutput, level)

	// 开发环境与生产环境的差异化配置
	var logger *zap.Logger
	if conf.GetString("env") != "prod" {
		logger = zap.New(core,
			zap.Development(),
			zap.AddCaller(),
			zap.AddStacktrace(zap.ErrorLevel),
		)
	} else {
		logger = zap.New(core,
			zap.AddCaller(),
			zap.AddStacktrace(zap.ErrorLevel),
		)
	}

	// 添加服务类型标识
	serviceTypeField := zap.String("service", serviceTypeToString(serviceType))
	logger = logger.With(serviceTypeField)

	return &Logger{logger}
}

// ensureDirExists 确保日志目录存在
func ensureDirExists(filePath string) error {
	dir := filepath.Dir(filePath)
	return os.MkdirAll(dir, 0755)
}

// serviceTypeToString 将服务类型转换为字符串
func serviceTypeToString(serviceType ServiceType) string {
	switch serviceType {
	case API:
		return "api"
	case Task:
		return "task"
	default:
		return "unknown"
	}
}

// timeEncoder 自定义时间编码器，提供高精度时间戳
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000000000"))
}

// WithValue Adds a field to the specified context
func (l *Logger) WithValue(ctx context.Context, fields ...zapcore.Field) context.Context {
	if c, ok := ctx.(*gin.Context); ok {
		ctx = c.Request.Context()
		c.Request = c.Request.WithContext(context.WithValue(ctx, ctxLoggerKey, l.WithContext(ctx).With(fields...)))
		return c
	}
	return context.WithValue(ctx, ctxLoggerKey, l.WithContext(ctx).With(fields...))
}

// WithContext Returns a zap instance from the specified context
func (l *Logger) WithContext(ctx context.Context) *Logger {
	if c, ok := ctx.(*gin.Context); ok {
		ctx = c.Request.Context()
	}
	zl := ctx.Value(ctxLoggerKey)
	ctxLogger, ok := zl.(*zap.Logger)
	if ok {
		return &Logger{ctxLogger}
	}
	return l
}
