package api

import (
	"errors"
	"fmt"
	"net/url"
	"nrhe-train/log"
	"time"

	"nrhe-train/db/model"
	"nrhe-train/db/repo"
	"nrhe-train/utils"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

type UserLoginPasswordReq struct {
	LoginName string `json:"loginName"`
	Password  string `json:"password"`
	Role      string `json:"role"`
}

func UserLoginPassword(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	var form UserLoginPasswordReq
	err := c.ShouldBindJSON(&form)
	if err != nil {
		return nil, err
	}

	// 查找用户:根据longinName/password/role是否在roles中
	user := &model.User{}
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionUser,
		Query: repo.Map{
			"loginName": form.LoginName,
			"password":  utils.UtilMd5(form.Password),
			"roles":     bson.M{"$elemMatch": bson.M{"$eq": form.Role}},
		},
	}, user)
	if err != nil {
		return nil, err
	}
	if !found {
		return nil, errors.New("账号/密码/角色不正确")
	}

	jwtU := &JWTUser{ID: user.GetID()}
	token, _, err := apictx.Svc.JWT.JwtCreateToken(jwtU)
	if err != nil {
		return nil, err
	}

	// 前端返回处理
	user.Password = ""
	out := map[string]interface{}{
		"token": token,
		"user":  user,
	}
	return out, nil
}

// 用户唯一
// db.users.createIndex({ nid: 1 }, { unique: true })
func CreateUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}

	user := &model.User{}
	err = c.ShouldBindJSON(&user)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	// 验证登录名是否存在
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionUser,
		Query:       repo.Map{"loginName": user.LoginName},
	}, user)
	if err != nil {
		return nil, err
	}
	if found {
		return nil, errors.New("该账号已存在")
	}

	// student,teacher,admin
	if len(user.Roles) < 1 {
		user.Roles = []string{"student"}
	}
	user.Password = UtilMd5(user.Password)
	user.CreateTime = time.Now()
	user.UpdateTime = time.Now()
	return repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, &user)
}

func DeleteUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	_id := c.Param("id")
	id, _ := primitive.ObjectIDFromHex(_id)
	if id.IsZero() {
		return nil, errors.New("id错误")
	}
	return repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionUser, _id)
}

type BatchDeleteUserReq struct {
	Ids []string `json:"ids"`
}

func BatchDeleteUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	var form BatchDeleteUserReq
	err = c.ShouldBindJSON(&form)
	if err != nil {
		return nil, errors.New("参数错误")
	}
	if len(form.Ids) > 0 {
		for _, id := range form.Ids {
			repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionUser, id)
		}
	}
	return true, nil
}

// 用户列表
// /user/list?role=student&name=xxx&nid=xxx&page=1&size=10
func UserList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isStudent, err := IsStudent(c, apictx)
	if err != nil {
		return nil, err
	}
	if isStudent {
		return nil, errors.New("没有权限")
	}
	page, size, query := UtilQueryPageSize(c)
	role := c.Query("role")
	name := c.Query("name")

	if len(role) > 0 {
		query["roles"] = bson.M{"$elemMatch": bson.M{"$eq": role}}
	}
	if len(name) > 0 {
		query["name"] = bson.M{"$regex": name, "$options": "$i"}
	}

	return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
		CollectName: repo.CollectionUser,
		Page:        page,
		Size:        size,
		Query:       query,
		Sort:        bson.D{bson.E{Key: "createTime", Value: -1}, bson.E{Key: "_id", Value: -1}},
		Project:     []string{"name", "loginName", "avatar", "roles", "createTime", "updateTime"},
	})

}

func UserDetail(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	_id := c.Param("id")
	id, _ := primitive.ObjectIDFromHex(_id)
	if id.IsZero() {
		return nil, errors.New("id错误")
	}
	return GetUserById(apictx, _id)
}

func UpdateUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	// 验证是否为管理员
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	user := &model.User{}
	err = c.ShouldBindJSON(&user)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	if user.Id.IsZero() {
		return nil, errors.New("id错误")
	}

	if len(user.Password) > 0 {
		user.Password = UtilMd5(user.Password)
	}
	result, err := repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionUser, user.Id.Hex(), user)
	if err != nil {
		return nil, errors.New("更新失败,请检查编码是否重复")
	}
	return result, err
}

// 获取自己的信息
func UserProfile(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	return GetUserById(apictx, apictx.User.ID)
}

// func UserLearnInc(c *gin.Context, apictx *ApiSession) (interface{}, error) {
// 	_time := c.Query("t")
// 	increase, _ := strconv.Atoi(_time)
// 	if increase < 1 {

// 		return false, fmt.Errorf("增加学习时长小于1: %d", increase)
// 	}
// 	userInfo, err := GetUserById(apictx, apictx.User.ID)
// 	if err != nil {
// 		return false, errors.New("未找到该用户信息")
// 	}
// 	learnTime := userInfo.LearnTime
// 	// 增加学习时长
// 	newTime := learnTime + increase
// 	_, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionUser, apictx.User.ID, &model.User{LearnTime: newTime})
// 	if err != nil {
// 		fmt.Println(err)
// 		log.Error(err)
// 		return false, errors.New("更新学习时长出错")
// 	}
// 	return true, nil
// }

// 根据id获取用户信息
func GetUserById(apictx *ApiSession, id string) (*model.User, error) {
	user := &model.User{}
	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionUser,
		Query:       repo.Map{"_id": id},
	}, user)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if !found {
		return nil, errors.New("未找到该数据")
	}
	user.Password = ""
	return user, nil
}

// 是否是管理员
func IsAdmin(c *gin.Context, apictx *ApiSession) (bool, error) {
	user, err := GetUserById(apictx, apictx.User.ID)
	if err != nil {
		return false, err
	}
	for _, v := range user.Roles {
		if v == "admin" {
			return true, nil
		}
	}
	return false, nil
}

// 是否是老师
func IsTeacher(c *gin.Context, apictx *ApiSession) (bool, error) {
	user, err := GetUserById(apictx, apictx.User.ID)
	if err != nil {
		return false, err
	}
	for _, v := range user.Roles {
		if v == "teacher" {
			return true, nil
		}
	}
	return false, nil
}

// 是否是学生
func IsStudent(c *gin.Context, apictx *ApiSession) (bool, error) {
	user, err := GetUserById(apictx, apictx.User.ID)
	if err != nil {
		return false, err
	}
	for _, v := range user.Roles {
		if v == "student" {
			return true, nil
		}
	}
	return false, nil
}

// 导入用户
func ImportUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	file, _, err := c.Request.FormFile("file")
	if err != nil {
		return nil, errors.New("文件错误")
	}
	excel, err := excelize.OpenReader(file)
	if err != nil {
		return nil, err
	}
	excelIndex := excel.GetActiveSheetIndex()
	sheetName := excel.GetSheetName(excelIndex)
	users, err := excel.GetRows(sheetName)
	if err != nil {
		return nil, err
	}
	errors := []string{}

	if len(users) > 0 {
		for index, us := range users {
			rowNum := index + 1
			// 标题行
			if index == 0 {
				continue
			}
			// 表头
			if index == 1 {
				continue
			}
			// 去除可能的空行
			if len(us) == 0 {
				continue
			}
			// 用户名name 编号nid 密码password 角色roles
			user := &model.User{}
			user.LoginName = us[0]
			user.Nid = us[1]
			if len(us[0]) == 0 {
				errors = append(errors, fmt.Sprintf("第%d行错误: %s", rowNum, "账号不能为空"))
				continue
			}
			// !查询用户,确保账号名唯一,用数据库唯一索引约束:db.users.createIndex({ loginName: 1 }, { unique: true })

			roles := []string{}
			if us[2] == "管理员" {
				roles = []string{"admin"}
			}
			if us[2] == "教员" {
				roles = []string{"teacher"}
			}
			if us[2] == "学员" {
				roles = []string{"student"}
			}
			user.Roles = roles
			user.Password = UtilMd5(us[3])
			if len(us[3]) == 0 {
				user.Password = UtilMd5("123456")
			} else if len(us[3]) == 32 {
				user.Password = us[3]
			}

			user.CreateTime = time.Now()
			user.UpdateTime = time.Now()

			_, err = repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, user)
			if err != nil {
				errors = append(errors, fmt.Sprintf("第%d行错误: %s", rowNum, "保存数据失败, 请检查数据格式是否正确/账号是否重复"))
				log.Error(err)
			}

		}
	}

	return errors, nil
}

// 导出用户
func ExportUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	isAdmin, err := IsAdmin(c, apictx)
	if err != nil {
		return nil, err
	}
	if !isAdmin {
		return nil, errors.New("没有权限")
	}
	f := excelize.NewFile()
	index, _ := f.NewSheet("Sheet1")
	f.SetActiveSheet(index)
	f.SetDefaultFont("宋体")

	testExcel := NewUserExcel(f)
	testExcel.Title = "用户信息"

	_, _, query := UtilQueryPageSize(c)
	// 获取试题列表
	users := make([]*model.User, 0)
	err = repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
		CollectName: repo.CollectionUser,
		Query:       query,
		Sort:        bson.M{"createTime": 1},
	}, &users)
	if err != nil {
		return nil, err
	}
	testExcel.Content = users
	testExcel.Draws()
	fileName := url.PathEscape("用户信息.xlsx")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+fileName)
	c.Header("Content-Transfer-Encoding", "binary")

	err = f.Write(c.Writer)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// 下载用户模板
func UserTmplate(c *gin.Context, apictx *ApiSession) (interface{}, error) {
	filename := "用户信息模板.xlsx"
	// url.PathEscape将字符串中的特殊字符进行编码，使其符合URL规范
	filename = url.PathEscape(filename)

	// 设置下载的文件名
	c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))

	// 设置文件类型
	c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

	c.File("./template/用户信息模板.xlsx")
	return nil, nil
}
