package router

import (
	"exam_system/dao"
	"exam_system/entity"
	"exam_system/result"
	"exam_system/service"
	"exam_system/utils"
	"exam_system/vo"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"net/http"
	"strconv"
	"strings"
)

func User(router *RouterPlus) {

	// 用户个人(管理员,用户)
	router.GET("/user", UserInfo)
	router.PUT("/user", UpdateUser)

	r := router.Group("/admin")
	{
		// 用户详情
		r.GET("/user/:sid", AdminUserDetail)

		// 用户列表
		r.GET("/user/list", AdminUserList)

		// 添加用户
		r.POST("/user", AdminAddUser)

		// 修改用户信息
		r.PUT("/user", AdminUpdateUser)

		// 删除用户
		r.DELETE("/user/:ids", AdminDeleteUser)

		// 导入用户
		r.POST("/user/upload", AdminUserImport)

		// 导出用户
		r.routerGroup.GET("/user/download", AdminDownload)

		// 模板下载
		r.routerGroup.GET("/user/template", AdminUserTemplate)
	}

}

// 用户操作
func UserInfo(c *gin.Context) *result.Result {
	id, exists := c.Get("id")
	if !exists {

		return result.USER_IS_NOT_EXISTED
	}
	return dao.FindUserbyId(id.(int))
}

func UpdateUser(c *gin.Context) *result.Result {
	var body struct {
		entity.User
		UserType string `json:"user_type,omitempty"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		return result.PASSWORD_ERROR
	}

	status := entity.UNDER_REVIEW
	body.Status = &status
	roleNames := c.GetStringSlice("role")
	for _, roleName := range roleNames {
		if roleName == "admin" {
			status = entity.NORMAL
			body.Status = &status
			break
		}
	}

	id := c.GetInt("id")
	body.ID = id

	return dao.UpdateUser(&body.User, body.UserType)
}

// 管理员操作

func AdminUserDetail(c *gin.Context) *result.Result {
	sid := c.Param("sid")
	if sid == "" {
		return result.PARAM_ERROR
	}
	res := dao.FindUserbySid(sid)
	if res.Code != result.SUCCESS.Code {
		return res
	}
	userVo := res.Data.(vo.UserVo)
	userVo.Password = ""

	return res.SetData(userVo)
}

func AdminUserList(c *gin.Context) *result.Result {
	page, size, sort, query, err := utils.Page(c)
	if err != nil {
		return result.PARAM_ERROR
	}
	return dao.FindUserList(page, size, sort, query)
}

func AdminAddUser(c *gin.Context) *result.Result {
	var body struct {
		entity.User
		UserType string `json:"user_type,omitempty"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		return result.PARAM_ERROR
	}
	if body.Username == "" || body.Password == "" || body.Sid == "" {
		return result.PARAM_ERROR
	}
	status := entity.NORMAL
	body.Status = &status
	return service.AddUser(&body.User, body.UserType)
}

func AdminUpdateUser(c *gin.Context) *result.Result {
	var body struct {
		entity.User
		UserType string `json:"user_type,omitempty"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		return result.PARAM_ERROR
	}
	if body.ID == 0 {
		return result.PARAM_ERROR
	}

	status := entity.NORMAL
	body.Status = &status

	return dao.UpdateUser(&body.User, body.UserType)
}

func AdminDeleteUser(c *gin.Context) *result.Result {
	idStr := c.Param("ids")
	if idStr == "" {
		return result.PARAM_ERROR
	}

	ids := strings.Split(idStr, ",")

	return dao.DeleteUsers(ids)
}

func AdminUserImport(c *gin.Context) *result.Result {

	fh, _ := c.FormFile("file")
	termIdStr := c.PostForm("term_id")
	classIdStr := c.PostForm("class_id")
	file, err := fh.Open()

	if termIdStr != "" {
		var termId int
		termId, err = strconv.Atoi(termIdStr)
		if err != nil {
			return result.UNKNOW_ERROR.SetMsg(err.Error())
		}

		var classId int
		if classIdStr != "" {
			classId, err = strconv.Atoi(classIdStr)
			if err != nil {
				return result.UNKNOW_ERROR.SetMsg(err.Error())
			}
		}
		return dao.InsertBatchUserByTermId(file, termId, classId)
	}

	if classIdStr != "" {
		var classId int
		classId, err = strconv.Atoi(classIdStr)
		if err != nil {
			return result.UNKNOW_ERROR.SetMsg(err.Error())
		}

		return dao.InsertBatchUserByClassId(file, classId)
	}

	return dao.InsertBatchUser(file)
}

func AdminDownload(c *gin.Context) {
	file, err := excelize.OpenFile(utils.StudentPath)
	if err != nil {
		c.JSON(http.StatusOK, result.UNKNOW_ERROR.SetMsg(err.Error()))
	}

	res := dao.DownloadUserInfo(file)
	if res.Code != result.SUCCESS.Code {
		c.JSON(http.StatusOK, res)
	}

	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename=考生信息导出.xlsx")
	c.Header("Content-Transfer-Encoding", "binary")

	_ = file.Write(c.Writer)
}

func AdminUserTemplate(c *gin.Context) {

	c.Writer.Header().Add("Content-Disposition", "attachment; filename=试题模板.zip")
	c.Writer.Header().Set("Content-Type", "application/zip")
	c.File(utils.StuTemplatePath)
}
