package router

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

func Subject(router *RouterPlus) {

	r := router.Group("/admin")
	{

		// 添加试题
		r.POST("/subject", AdminAddSubject)

		// 获取试题
		r.GET("/subject/:id", AdminGetSubject)

		// 获取试题列表
		r.GET("/subject/list", AdminSubjectList)

		// 修改试题
		r.PUT("/subject", AdminUpdateSubject)

		// 删除试题
		r.DELETE("/subject/:ids", AdminDeleteSubject)

		// 上传试题
		r.POST("/subject/upload/:id", AdminUploadSuject)

		// 下载试题
		r.routerGroup.GET("/subject/:id/:type", AdminDownloadSubject)

		// 下载试题模板
		r.routerGroup.GET("/subject/template", AdminSubjectTemplate)

	}

}

func AdminAddSubject(c *gin.Context) *result.Result {
	var subject entity.Subject
	err := c.ShouldBindJSON(&subject)
	if err != nil || !CheckSubject(&subject) {
		return result.PARAM_ERROR
	}

	return dao.AddSubject(&subject)
}

func AdminGetSubject(c *gin.Context) *result.Result {
	id := c.Param("id")
	if id == "" {
		return result.UNKNOW_ERROR
	}
	return dao.SubjectDetail(id)
}

func AdminSubjectList(c *gin.Context) *result.Result {
	page, size, sort, query, err := utils.Page(c)

	if err != nil {
		return result.PARAM_ERROR
	}
	return dao.SubjectList(page, size, sort, query)
}

func AdminUpdateSubject(c *gin.Context) *result.Result {
	var subject entity.Subject
	err := c.ShouldBindJSON(&subject)
	if err != nil || subject.Id == 0 || subject.Type == nil {
		return result.PARAM_ERROR
	}
	return dao.UpdateSubject(&subject)
}

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

	idStr := c.Param("ids")
	if idStr == "" {
		return result.PARAM_ERROR
	}

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

	return dao.DeleteSubjects(ids)
}

func CheckSubject(s *entity.Subject) bool {

	if s.Type == nil || s.QbId == 0 || s.Question == "" {
		return false
	}

	s.Answer = strings.TrimSpace(s.Answer)

	if *s.Type == 0 || *s.Type == 1 {
		match, _ := regexp.MatchString("^[1-4]?$", s.Answer)
		if s.OptA == "" || s.OptB == "" || s.OptC == "" || s.OptD == "" || !match {
			return false
		}
	}

	if *s.Type == 2 {
		if s.OptA == "" || s.OptB == "" || s.OptC == "" || s.OptD == "" {
			return false
		}
		match1, _ := regexp.MatchString("^[1-4]{0,4}$", s.Answer)
		match2, _ := regexp.MatchString(`([\s\S])[\s\S]*?\1`, s.Answer)
		if !match1 || match2 {
			return false
		}
	}

	if *s.Type == 3 {
		match, _ := regexp.MatchString("^[1-2]?$", s.Answer)
		if !match {
			return false
		}
	}
	return true
}

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

	id := c.Param("id")
	fh, _ := c.FormFile("file")
	file, err := fh.Open()
	if err != nil {
		return result.UNKNOW_ERROR.SetMsg(err.Error())
	}

	return dao.AddSubjectBatch(file, id)
}

func AdminSubjectTemplate(c *gin.Context) {

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

func AdminDownloadSubject(c *gin.Context) {
	idStr := c.Param("id")
	tpStr := c.Param("type")

	id, err := strconv.Atoi(idStr)
	if err != nil {
		c.JSON(http.StatusOK, result.UNKNOW_ERROR.SetMsg(err.Error()))
	}
	tp, err := strconv.Atoi(tpStr)
	if err != nil {
		c.JSON(http.StatusOK, result.UNKNOW_ERROR.SetMsg(err.Error()))
	}

	var path string
	switch tp {
	case entity.SINGEL_CHOICE:
		path = utils.SingelChoicePath
	case entity.Judgement:
		path = utils.JudgementPath
	case entity.MULTIPLE_CHOICE:
		path = utils.MultipleChoicePath
	case entity.Completion:
		path = utils.CompletionPath
	}

	file, err := excelize.OpenFile(path)
	if err != nil {
		c.JSON(http.StatusOK, result.UNKNOW_ERROR.SetMsg(err.Error()))
	}

	res := dao.DownloadSubject(file, id, tp)
	if res.Code != result.SUCCESS.Code {
		file.Close()
		c.JSON(http.StatusOK, res)
	}else{
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.xlsx", res.Data.(string)))
		c.Header("Content-Transfer-Encoding", "binary")
		_ = file.Write(c.Writer)
	}


}
