package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	rotatelogs "github.com/lestrrat/go-file-rotatelogs"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"gogs.daxia.dev/huanan/pkg.daxia.dev/db"
	"gogs.daxia.dev/huanan/pkg.daxia.dev/rdb"
	"nn.daxia.dev/model"
	"nn.daxia.dev/online"
	"nn.daxia.dev/router"
)

func main() {
	defer func() {
		if err := recover(); err != nil {
			logrus.Error(err)
			fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
		}
	}()

	viper.Set("gormlog", true)
	viper.AddConfigPath("conf")
	viper.AddConfigPath("configs/qznn")

	viper.SetConfigName("config")
	viper.SetConfigType("yaml")

	viper.AutomaticEnv()
	viper.SetEnvPrefix("web")
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// 从环境变量总读取
	err := viper.ReadInConfig()
	if err != nil {
		logrus.Fatal(err)
	}

	initCoreDump()
	initLog()

	online.Init()

	logrus.Println("==================")
	logrus.Println(viper.AllSettings())
	logrus.Println("==================")

	flag.Parse()
	log.SetFlags(0)

	gin.SetMode(viper.GetString("runmode"))

	// 初始化空的服务器
	app := gin.New()

	// 保存中间件
	middlewares := []gin.HandlerFunc{}

	// 路由
	router.Load(
		app,
		middlewares...,
	)

	isDebug := viper.GetBool("is_debug")
	logrus.Println("debug: ", isDebug)
	isDebug = false
	if isDebug {
		db.InitTest()
	} else {
		db.Init()
	}

	createDBTable()
	clearRoomData()

	err = rdb.InitClient()
	if err != nil {
		logrus.Fatal(err)
	}

	// 服务器域名的地址和端口
	addr := viper.GetString("addr")
	logrus.Infof("启动服务器在 http address: %s", addr)

	srv := &http.Server{
		Addr:    addr,
		Handler: app,
	}

	// 启动服务
	if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		logrus.Fatalf("listen: %s\n", err)
	}
}

func initLog() {
	if viper.GetBool("log.logrus_json") {
		logrus.SetFormatter(&logrus.JSONFormatter{
			DisableHTMLEscape: true,
		})
	}

	// log.logrus_level
	switch viper.GetString("log.logrus_level") {
	case "trace":
		logrus.SetLevel(logrus.TraceLevel)
	case "debug":
		logrus.SetLevel(logrus.DebugLevel)
	case "info":
		logrus.SetLevel(logrus.InfoLevel)
	case "warn":
		logrus.SetLevel(logrus.WarnLevel)
	case "error":
		logrus.SetLevel(logrus.ErrorLevel)
	}

	// log.logrus_file
	logrusFile := viper.GetString("log.logrus_file")
	os.MkdirAll(filepath.Dir(logrusFile), os.ModePerm)

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

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

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

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

	if viper.GetBool("log.logrus_console") {
		logrus.SetOutput(io.MultiWriter(logWriter, os.Stdout))
	} else {
		logrus.SetOutput(logWriter)
	}

	// default
	logrus.SetReportCaller(true)
}

const panicFile = "./logs/panic.log"

func initCoreDump() error {
	if runtime.GOOS == "windows" {
		return nil
	}

	log.Println("init panic file in unix mode")
	file, err := os.OpenFile(panicFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		logrus.Error(err)
		return err
	}

	if err = syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
		return err
	}

	return nil
}

func createDBTable() error {
	(model.User{}).Init()
	(model.Room{}).Init()
	(model.GameOrder{}).Init()

	return nil
}

func clearRoomData() error {
	// roomModel := (model.Room{})
	// chairList := []string{"chair1", "chair2", "chair3", "chair4", "chair5"}
	// for _, item := range chairList {
	// 	err := db.GetDB().Model(roomModel).Update(item, 0).Error
	// 	if err != nil {
	// 		logrus.Error(err)
	// 		return err
	// 	}
	// }

	return nil
}
