package cmn

import (
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"time"

	"github.com/fatih/color"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type LogStruct struct {
	Writer    io.Writer
	File      *os.File
	Print_cfg bool // 此条打印到控制台
	Separator string
}

type LogFileld map[string]string

var (
	LOG_DEBUG   = "Debug"
	LOG_ERROR   = "Error"
	LOG_Info    = "Info"
	LOG_WARNING = "Warning"
)

// 日志颜色
var colors = map[string]func(a ...interface{}) string{
	"Warning": color.New(color.FgYellow).Add(color.Bold).SprintFunc(),
	"Panic":   color.New(color.BgRed).Add(color.Bold).SprintFunc(),
	"Error":   color.New(color.FgRed).Add(color.Bold).SprintFunc(),
	"Info":    color.New(color.FgCyan).Add(color.Bold).SprintFunc(),
	"Debug":   color.New(color.FgWhite).Add(color.Bold).SprintFunc(),
}

// 不同级别前缀与时间的间隔,保持宽度一致
var spaces = map[string]string{
	"Warning": "",
	"Panic":   "  ",
	"Error":   "  ",
	"Info":    "   ",
	"Debug":   "  ",
}

// 运行日志静态类
var runLogStatic = LogStruct{}

// 控制台打印
// Warning Panic Error Info Debug
func Pln(prefix string, msg string) {
	fmt.Printf(
		"%s%s %s %s\n",
		colors[prefix]("["+prefix+"]"),
		spaces[prefix],
		time.Now().Format(TimeFormatMode1),
		msg,
	)
}

// 控制台打印,支持颜色
func Print(color, key, msg string) {
	fmt.Printf(
		"%s%s %s\n",
		colors[color](key),
		time.Now().Format(TimeFormatMode1),
		msg,
	)
}

// func Debug(a ...interface{}) {
// 	fmt.Print("[Debug] ")
// 	fmt.Println(a...)
// }

// // 错误并退出
// func ErrorExit(err_title, err_msg string) {
// 	newLog := NewLog("err.log")

// 	Pln("Error", err_title+err_msg)
// 	newLog.Error(err_title, err_msg)
// 	os.Exit(1)
// }

// 写入日志的文件
func NewLog(log_file_name string) *LogStruct {
	logStruct := &LogStruct{}
	logStruct.Separator = ""
	logDir := path.Dir(log_file_name)
	ok, _ := PathExists(logDir)
	if !ok {
		if err := os.MkdirAll(logDir, 0666); err != nil {
			fmt.Println("创建日志文件错误", err.Error())
		}
	}
	_, err := os.Stat(log_file_name)
	if err != nil {
		f, _ := os.Create(log_file_name)
		logStruct.File = f
		logStruct.Writer = io.MultiWriter(f)
	} else {
		f, _ := os.OpenFile(log_file_name, os.O_APPEND|os.O_WRONLY, 0666)
		logStruct.File = f
		logStruct.Writer = io.MultiWriter(f)
	}
	return logStruct
}

// 运行日志直接静态
func RunLog() *LogStruct {
	// 按小时/日/月/年
	// 先判断文件(夹)是否存在。否多级创建
	log_file := "res/runtime/log/"
	ok, _ := PathExists(log_file)
	if !ok {
		os.MkdirAll(log_file, 0777)
	}
	log_file_name := log_file + time.Unix(time.Now().Unix(), 1).Format("2006-01-02") + ".log"
	_, err := os.Stat(log_file_name)
	runLogStatic.Separator = "|"
	if err != nil {
		f, _ := os.Create(log_file_name)
		runLogStatic.File = f
		runLogStatic.Writer = io.MultiWriter(f)
	} else {
		if runLogStatic.File == nil {
			f, _ := os.OpenFile(log_file_name, os.O_APPEND|os.O_WRONLY, 0666)
			runLogStatic.File = f
			runLogStatic.Writer = io.MultiWriter(f)
		}
	}
	return &runLogStatic
}

func (t *LogStruct) Write(content string) (n int, err error) {

	return io.WriteString(t.Writer, content)
}

func (t *LogStruct) Format(log_type string, content string) (n int, err error) {
	content = log_type + spaces[log_type] + " " + GetTime() + " " + content + "\n"
	return t.Write(content)
}

func (t *LogStruct) Info(content ...string) (n int, err error) {
	str := ""
	for i := 0; i < len(content); i++ {
		if i != 0 {
			str += t.Separator + content[i]
		} else {
			str += content[i]
		}
	}
	n, err = t.Format("Info", str)
	if t.Print_cfg == true {
		Pln("Info", str)
		t.Print_cfg = false
	}
	return
}

func (t *LogStruct) Debug(content string) {
	t.Format("Debug", content)
	if t.Print_cfg == true {
		Pln("Debug", content)
		t.Print_cfg = false
	}
}

func (t *LogStruct) Error(content ...string) {
	content_str := ""
	for i := 0; i < len(content); i++ {
		if i != 0 {
			content_str += t.Separator + content[i]
		} else {
			content_str += content[i]
		}
	}
	t.Format("Error", content_str)
	if t.Print_cfg == true {
		Pln("Error", content_str)
		t.Print_cfg = false
	}
}

// // 打印错误
// func (t *LogStruct) ErrorPrint(key, value string) {
// 	t.Print_cfg = true
// 	t.Error(key, value)
// }

// // 打印Debug
// func (t *LogStruct) DebugPrint(key, value string) {
// 	t.Print_cfg = true
// 	content := key + " " + value
// 	t.Debug(content)
// }

// func (t *LogStruct) Print() *LogStruct {
// 	t.Print_cfg = true
// 	return t
// }

// func (t *LogStruct) FormatFileld(field LogFileld) string {
// 	str := ""
// 	for k, v := range field {
// 		str += k + ":\"" + v + "\"" + t.Separator
// 	}
// 	if len(str) != 0 {
// 		str = str[0 : len(str)-1]
// 	}
// 	return str
// }

// TODO(GgoCoder) 日志轮转
func InitLogger(fileName string, level zapcore.LevelEnabler) *zap.SugaredLogger {
	fileWriteSyncer := getLogWriter(fileName)
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(fileWriteSyncer, zapcore.AddSync(os.Stdout)), level)
	logger := zap.New(core, zap.AddCaller())
	return logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	logConf := zap.NewProductionEncoderConfig()
	logConf.EncodeTime = zapcore.ISO8601TimeEncoder
	logConf.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(logConf)
}

func getLogWriter(fileName string) zapcore.WriteSyncer {
	file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
	if err != nil {
		log.Panic("failed to create log file", fileName)
	}
	return zapcore.AddSync(file)
}