package controllers

import (
	"exhibitionCentre/base"
	"exhibitionCentre/cache"
	"exhibitionCentre/config"
	"exhibitionCentre/logging"
	"exhibitionCentre/models"
	"exhibitionCentre/utils"
	"fmt"
	"text/template"
)

type LoginRequest struct {
	Email string `json:"email"`
	Code  string `json:"code"`
}

type EmailInfo struct {
	Email string `json:"email"`
}

func Login(router *base.Router) (int, []byte) {
	// 检查登陆状态，cookie中令牌未过期则直接进入dashboard页面
	if _, authorized := LoginAuthenticate(router); authorized {
		Redirect(router, "/manage/dashboard")
		return 0, nil
	}

	// 检查是否包含登陆信息，有则进入登录逻辑
	if router.Data != nil && len(router.Data) > 0 {
		return loginInternal(router)
	}

	// 加载登陆界面
	page, err := template.ParseFiles("./view/html/login.html")
	if err != nil {
		logging.Log.Error("加载登陆页面失败: ", err.Error())
		return 404, utils.SerializeErrorData("")
	}
	page.Execute(router.Writer, nil)
	logging.Log.Infof("打开登陆界面，客户端ip(%s)\n", utils.RemoteIp(router.Req))
	return 200, nil
}

func Logout(router *base.Router) (int, []byte) {
	DeleteToken(router)
	return 200, []byte("{}")
}

func GetVerificationCode(router *base.Router) (int, []byte) {
	// 解析request数据
	var info EmailInfo
	if err := utils.JsonParse(router.Data, &info); err != nil {
		logging.Log.Error("解析数据失败: ", err.Error())
		return 403, utils.SerializeErrorData("获取验证码失败!")
	}

	// 数据库查询用户
	user, _ := models.GetUser(info.Email)
	if user == nil {
		if utils.StringArrayContains(config.Config.Role.Administrators, info.Email) {
			logging.Log.Infof("创建管理员(%s)\n", info.Email)
			user = models.AddAdministrator(info.Email, "")
		}
	}

	// 检查用户是否存在
	if user == nil {
		logging.Log.Errorf("获取验证码时未找到用户(%s)", info.Email)
		return 404, utils.SerializeErrorData(fmt.Sprintf("该用户(%s)不存在!", info.Email))
	}

	// 生成验证码
	code := utils.GenerateVerificationCode(6)
	logging.Log.Infof("用户(%s)生成验证码: %s\n", user.Email, code)

	// 缓存验证码
	if !cache.CreateVerificationCode(user.Email, code) {
		logging.Log.Errorf("缓存验证码失败，用户(%s)", info.Email)
		return 403, utils.SerializeErrorData("获取验证码失败!")
	}

	// 发送验证码邮件
	if !utils.SendVerificationCode(info.Email, code) {
		logging.Log.Errorf("发送验证码邮件失败，用户(%s)，验证码(%s)\n", info.Email, code)
		return 403, utils.SerializeErrorData("获取验证码失败!")
	}
	logging.Log.Infof("发送验证码邮件成功，用户(%s)，验证码(%s)\n", info.Email, code)
	return 200, []byte("{}")
}

func loginInternal(router *base.Router) (int, []byte) {
	// 解析request数据
	var info LoginRequest
	if err := utils.JsonParse(router.Data, &info); err != nil {
		logging.Log.Errorf("解析登陆数据失败: %s\n", err.Error())
		return 403, utils.SerializeErrorData("登陆失败!")
	}

	// 检查对应email的用户是否存在
	user, err := models.GetUser(info.Email)
	if err != nil {
		logging.Log.Errorf("登陆时未找到用户(%s), err: %v", info.Email, err.Error())
		return 404, utils.SerializeErrorData(fmt.Sprintf("该用户(%s)不存在!", info.Email))
	}

	// 获取验证码缓存
	code := cache.GetVerificationCode(info.Email)
	if code == "" || code != info.Code {
		if code == "" {
			logging.Log.Warningf("未找到缓存验证码或验证码过期，用户(%s)", info.Email)
		} else {
			logging.Log.Warningf("缓存验证码(%s)验证失败，用户(%s)，验证码(%s)", code, info.Email, info.Code)
		}
		return 403, utils.SerializeErrorData("验证码错误!")
	}

	// 删除缓存验证码
	cache.DeleteVerificationCode(info.Email)

	// 获取jwt令牌
	token, err := utils.GenerateJWT(user.ID, info.Email, int(user.Role))
	if err != nil {
		logging.Log.Errorf("登陆时生成令牌失败，用户(%s)", info.Email)
		return 401, utils.SerializeErrorData("登陆失败!")
	}

	// 设置客户端cookie
	SaveToken(token, router)

	return 200, []byte("{}")
}
