package app

import (
	"github.com/goccy/go-json"
	"github.com/gofiber/fiber/v2"
	"github.com/spf13/viper"
	"gofiber.study.skcks.cn/common/config"
	"gofiber.study.skcks.cn/common/errorx"
	"gofiber.study.skcks.cn/common/logger"
	"gofiber.study.skcks.cn/common/utils"
	"gofiber.study.skcks.cn/controller"
	"gofiber.study.skcks.cn/global"
	"gofiber.study.skcks.cn/services"
)

func Run() {
	err := viper.Unmarshal(global.Config)
	if err != nil {
		logger.Log.Fatalf("配置文件解析失败: %s", err)
	}

	utils.MainAppExec(func() {
		logger.Log.Debugf("\n%#v", global.Config)
	})

	reloadRedis(global.Config)
	reloadCaptcha(global.Config, global.Redis)
	reloadDataSources(global.Config)
	reloadJwt(global.Config)
	reloadSonyFlake(global.Config)
	reloadNanoId(global.Config)

	global.App = reloadApp(global.Config)

	if err := global.App.Listen(global.Config.Server.Addr); err != nil {
		logger.Log.Fatalf("[x] [Fiber] 致命错误: %s", err)
	}

}

func reloadApp(c *config.BasicConfig) *fiber.App {
	if global.App != nil {
		_ = global.App.Shutdown()
	}

	global.App = fiber.New(fiber.Config{
		JSONEncoder:   json.Marshal,
		JSONDecoder:   json.Unmarshal,
		Prefork:       c.Server.PreFork,
		CaseSensitive: c.Server.CaseSensitive,
		StrictRouting: c.Server.StrictRouting,
		ServerHeader:  c.Server.ServerHeader,
		ErrorHandler: func(ctx *fiber.Ctx, err error) error {
			code := fiber.StatusInternalServerError

			logger.Log.Errorf("%#v", err)

			if e, ok := err.(*fiber.Error); ok {
				logger.Log.Debugf("err %v", e)
				code = e.Code
				if code == fiber.StatusNotFound {
					return ctx.Status(fiber.StatusNotFound).JSON(errorx.NewErrorWithCode(code, "页面不存在"))
				}

			}

			err = ctx.Status(code).JSON(errorx.NewDefaultError(err.Error()))
			if err != nil {
				return ctx.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
			}

			return nil
		},
	})

	if c.Server.EnableRoutesMsg {
		routes(global.App)
	}

	// 路由注册
	controller.SwaggerHandler(global.App)
	controller.ErrorHandler(global.App)
	controller.RegisterController(global.App)

	// 初始化服务
	services.Init()

	global.App.Hooks().OnListen(func() error {
		utils.MainAppExec(func() {
			logger.Log.Infoln("[√] [服务启动完成]")
		})
		return nil
	})

	return global.App
}
