package logger

import (
	"bytes"
	"fmt"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var (
	AccessLogger = logrus.New()
	RouterLogger = logrus.New()
	ErrorLogger  = logrus.New()
	RdsLogger    *RdsLoggerWriter
)

type CustomLogger struct {
	File   string
	Logger *logrus.Logger
}

func New(LogFilePath string, RunMode string) {

	var err error
	_, err = os.Stat(LogFilePath)
	switch {
	case os.IsNotExist(err):
		err = os.MkdirAll(LogFilePath, os.ModePerm)
		if err != nil {
			panic(err)
		}
	case os.IsPermission(err):
		panic(err)
	}

	for _, item := range []CustomLogger{
		{File: "access.log", Logger: AccessLogger},
		{File: "router.log", Logger: RouterLogger},
		{File: "error.log", Logger: ErrorLogger},
	} {
		loggerToFile(LogFilePath, item.File, item.Logger, RunMode)
	}

	RdsLogger = newRdsLoggerWriter(LogFilePath, "rds.log", logrus.New(), RunMode)
}

type LogFormatter struct{}

func (s *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {

	var (
		file string
		dir  string
		l    int
	)

	local, _ := time.LoadLocation("Asia/Shanghai")
	timestamp := time.Now().In(local).Format("2006-01-02 15:04:05")

	if entry.Caller != nil {
		file = filepath.Base(entry.Caller.File)
		dir = filepath.Dir(entry.Caller.File)
		l = entry.Caller.Line
	}

	ssss, _ := os.Getwd()
	//fmt.Println(entry.Data)
	msg := fmt.Sprintf(
		"[GOID:%d] [%s] %s [%s/%s:%d] %s\n",
		getGID(),
		strings.ToUpper(entry.Level.String()),
		timestamp, strings.ReplaceAll(dir, ssss, ""), file, l,
		entry.Message)
	return []byte(msg), nil
}

func getGID() uint64 {
	b := make([]byte, 64)
	b = b[:runtime.Stack(b, false)]
	b = bytes.TrimPrefix(b, []byte("goroutine "))
	b = b[:bytes.IndexByte(b, ' ')]
	n, _ := strconv.ParseUint(string(b), 10, 64)
	return n
}

func loggerToFile(LogFilePath string, LogFileName string, LoggerInstance *logrus.Logger, RunMode string) {
	fileName := path.Join(LogFilePath, LogFileName)

	//writer := bufio.NewWriter(src)
	//LoggerInstance.SetOutput(writer)
	outSelect(LoggerInstance, RunMode)
	LoggerInstance.SetReportCaller(true)
	//LoggerInstance.SetFormatter(new(LogFormatter))

	logWriter, _ := rotatelogs.New(
		// 分割后的文件名称
		fileName+".%Y%m%d.log",

		// 生成软链,指向最新日志文件
		rotatelogs.WithLinkName(fileName),

		// 设置最大保存时间(2天)
		rotatelogs.WithMaxAge(2*24*time.Hour),

		// 设置日志切割时间间隔(1天)
		rotatelogs.WithRotationTime(24*time.Hour),
	)

	writeMap := lfshook.WriterMap{
		logrus.InfoLevel:  logWriter,
		logrus.FatalLevel: logWriter,
		logrus.DebugLevel: logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: logWriter,
		logrus.PanicLevel: logWriter,
	}

	lfHook := lfshook.NewHook(writeMap, &LogFormatter{})

	// 新增 Hook
	LoggerInstance.AddHook(lfHook)
}

func outSelect(LoggerInstance *logrus.Logger, RunMode string) {
	if RunMode != "debug" {
		src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
		if err != nil {
			panic(err)
		}
		LoggerInstance.SetOutput(src)
	} else {
		LoggerInstance.SetOutput(os.Stdout)
	}
}