package front

import (
	"encoding/json"
	"fmt"
	"github.com/dchest/captcha"
	"github.com/gorilla/sessions"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"math"
	mgo "mongodb"
	qu "qfw/util"
	"strconv"
	"strings"
	"sync"
	"time"
	. "util"
)

var store = sessions.NewCookieStore([]byte("jianyu_secret20210422"))

func (f *Front) Login() {
	defer qu.Catch()
	if f.Method() == "POST" {
		username := f.GetString("username")
		password := f.GetString("pwd")
		imgCode := f.GetString("imgCode")
		passwordEn := qu.SE.EncodeString(password)
		qu.Debug(username, passwordEn, imgCode)
		session, err := store.Get(f.Request, "dataTagLoginImgCode")
		if err != nil {
			qu.Debug("图片验证码session获取失败-%s \n", username)
			f.ServeJson(map[string]interface{}{
				"code":    0,
				"status":  false,
				"message": "获取失败",
			})
			return
		}
		code := qu.ObjToString(session.Values["dataTagLoginImgCode"])
		if code == "" {
			qu.Debug("图片验证码过期-%s \n", username)
			f.ServeJson(map[string]interface{}{
				"checked": false,
				"message": "图片验证码过期",
			})
			return
		}
		//if !captcha.VerifyString(code, imgCode) {
		//	qu.Debug("图片验证码错误-%s \n", username)
		//	f.ServeJson(map[string]interface{}{
		//		"checked":  false,
		//		"message": "图片验证码错误",
		//	})
		//	return
		//}
		query := map[string]interface{}{
			"s_login":    username,
			"s_password": passwordEn,
		}
		user, _ := Mgo.FindOne("s_user", query)
		checked := false
		if user != nil && len(*user) > 0 {
			checked = true
			f.SetSession("user", map[string]interface{}{
				"s_groupid": (*user)["s_groupid"],
				//"s_name":    (*user)["s_name"],
				"i_role":  (*user)["i_role"],
				"s_pwd":   password,
				"s_login": username,
				"id":      mgo.BsonIdToSId((*user)["_id"]),
			})
			UserMenu[username] = GetUserMenu(qu.IntAll((*user)["i_role"]))
		}
		f.ServeJson(map[string]interface{}{
			"checked": checked,
			"message": "账号或密码错误",
		})
	} else {
		_ = f.Render("login.html")
	}
}

// 获取图片验证码
func (f *Front) Code() {
	id := captcha.NewLen(4)
	//r := &http.Request{}
	f.Request.Header.Add("Cache-Control", "no-cache, no-store, must-revalidate")
	f.Request.Header.Add("Pragma", "no-cache")
	f.Request.Header.Add("Expires", "0")
	f.Request.Header.Add("Content-Type", "image/png")
	w := f.ResponseWriter
	session, err := store.Get(f.Request, "dataTagLoginImgCode")
	if err != nil {
		qu.Debug("session1获取失败")
		return
	}
	session.Values["dataTagLoginImgCode"] = id
	session.Options.MaxAge = 60
	if err := session.Save(f.Request, w); err != nil {
		qu.Debug("session1保存错误,验证码 ", id)
	}
	err2 := captcha.WriteImage(w, id, 90, 30)
	if err2 != nil {
		qu.Debug("生成图片验证码错误,验证码 ", id)
	}
	return
}

func (f *Front) Logout() {
	f.DelSession("user")
	f.Redirect("/")
}

func (f *Front) UserGroup() {
	defer qu.Catch()
	if f.Method() == "POST" {
		start, _ := f.GetInteger("start")
		limit, _ := f.GetInteger("length")
		draw, _ := f.GetInteger("draw")
		searchStr := f.GetString("search[value]")
		search := strings.TrimSpace(searchStr)
		query := map[string]interface{}{
			"b_delete": false,
		}
		if search != "" {
			query["$or"] = []interface{}{
				bson.M{"s_name": bson.M{"$regex": search}},
			}
		}

		data, _ := Mgo.Find("s_group", query, `{"i_createtime":-1}`, nil, false, start, limit)
		count := Mgo.Count("s_group", query)
		f.ServeJson(map[string]interface{}{
			"draw":            draw,
			"data":            data,
			"recordsFiltered": count,
			"recordsTotal":    count,
		})
	} else {
		_ = f.Render("user/user_group.html")
	}
}

func (f *Front) UserGroupNew() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		group := *qu.ObjToMap(data["group"])
		user := *qu.ObjToMap(data["user"])
		currenttime := time.Now().Unix()
		group["i_createtime"] = currenttime
		group["i_updatetime"] = currenttime
		group["b_delete"] = false
		gid := Mgo.Save("s_group", group) // 保存用户组
		if gid != "" {
			// 1、用户组管理员账号
			m1 := make(map[string]interface{})
			m1["s_groupid"] = gid
			m1["s_name"] = ""
			m1["s_login"] = group["s_name"]
			m1["s_password"] = qu.SE.EncodeString(qu.ObjToString(group["s_password"]))
			m1["i_power"] = "1"
			m1["s_phone"] = ""
			m1["i_createtime"] = currenttime
			m1["i_updatetime"] = currenttime
			m1["i_state"] = true
			m1["b_delete"] = false
			Mgo.Save("s_user", m1)
			// 2、质检员账号
			for i := 0; i < qu.IntAll(user["u1_size"]); i++ {
				m := make(map[string]interface{})
				m["s_groupid"] = gid
				m["s_name"] = ""
				m["s_login"] = qu.ObjToString(group["s_name"]) + "_zj_" + strconv.Itoa(i)
				m["s_password"] = qu.SE.EncodeString(qu.ObjToString(user["u1_pwd"]))
				m["i_power"] = "2"
				m["s_phone"] = ""
				m["i_createtime"] = currenttime
				m["i_updatetime"] = currenttime
				m["i_state"] = true
				m["b_delete"] = false
				Mgo.Save("s_user", m)
			}
			// 3、普通用户账号
			for i := 0; i < qu.IntAll(user["u2_size"]); i++ {
				m := make(map[string]interface{})
				m["s_groupid"] = gid
				m["s_name"] = ""
				m["s_login"] = qu.ObjToString(group["s_name"]) + "_" + strconv.Itoa(i)
				m["s_password"] = qu.SE.EncodeString(qu.ObjToString(user["u2_pwd"]))
				m["i_power"] = "3"
				m["s_phone"] = ""
				m["i_createtime"] = currenttime
				m["i_updatetime"] = currenttime
				m["i_state"] = true
				m["b_delete"] = false
				Mgo.Save("s_user", m)
			}
			f.ServeJson(map[string]interface{}{
				"rep": true,
			})
		} else {
			f.ServeJson(map[string]interface{}{
				"rep": false,
			})
		}
	} else {
		f.T["pwd"] = Password
		_ = f.Render("user/user_group_create.html", &f.T)
	}
}

func (f *Front) UserGroupState() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		b := Mgo.UpdateById("s_group", qu.ObjToString(data["id"]), map[string]interface{}{"$set": map[string]interface{}{"i_state": data["state"]}})
		f.ServeJson(map[string]interface{}{
			"rep": b,
		})
	}
}

func (f *Front) UserGroupStateBulk() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		qu.Debug(data)
		ids := strings.Split(qu.ObjToString(data["ids"]), ",")
		for _, k := range ids {
			b := Mgo.UpdateById("s_group", k, map[string]interface{}{"$set": map[string]interface{}{"i_state": data["state"]}})
			if !b {
				f.ServeJson(map[string]interface{}{
					"rep": b,
				})
			}
		}
		f.ServeJson(map[string]interface{}{
			"rep": true,
		})
	}
}

func (f *Front) UserGroupDel() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		qu.Debug(data)
		b := Mgo.UpdateById("s_group", qu.ObjToString(data["id"]), map[string]interface{}{"$set": map[string]interface{}{"b_delete": true}})
		f.ServeJson(map[string]interface{}{
			"rep": b,
		})
	}
}

func (f *Front) UserManage() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		gid := qu.ObjToString(data["gid"])
		draw, _ := f.GetInteger("draw")
		query := map[string]interface{}{"s_groupid": gid, "b_delete": false}
		info, b := Mgo.Find("s_user", query, nil, nil, false, -1, -1)
		count := Mgo.Count("s_user", query)
		if b && len(*info) > 0 {
			f.ServeJson(map[string]interface{}{
				"rep":             true,
				"data":            *info,
				"draw":            draw,
				"recordsFiltered": count,
				"recordsTotal":    count,
			})
		} else {
			f.ServeJson(map[string]interface{}{
				"rep": false,
			})
		}
	} else {
		f.T["gid"] = f.GetString("id")
		_ = f.Render("user/user_list.html", &f.T)
	}
}

func (f *Front) UserState() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		b := Mgo.UpdateById("s_user", qu.ObjToString(data["id"]), map[string]interface{}{"$set": map[string]interface{}{"i_state": data["state"]}})
		f.ServeJson(map[string]interface{}{
			"rep": b,
		})
	}
}

func (f *Front) UserDel() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		b := Mgo.UpdateById("s_user", qu.ObjToString(data["id"]), map[string]interface{}{"$set": map[string]interface{}{"b_delete": true}})
		f.ServeJson(map[string]interface{}{
			"rep": b,
		})
	}
}

func (f *Front) UserModify() {
	defer qu.Catch()
	if f.Method() == "POST" {
		data := GetPostForm(f.Request)
		b := Mgo.UpdateById("s_user", qu.ObjToString(data["id"]), map[string]interface{}{"$set": map[string]interface{}{"s_name": data["s_name"], "s_phone": data["s_phone"]}})
		f.ServeJson(map[string]interface{}{
			"rep": b,
		})
	}
}

func (f *Front) GroupList() {
	qu.Catch()
	query := map[string]interface{}{"b_delete": false, "i_state": true}
	field := map[string]interface{}{"s_name": 1, "s_personname": 1}
	info, b := Mgo.Find("s_group", query, nil, field, false, -1, -1)
	if b && len(*info) > 0 {
		f.ServeJson(map[string]interface{}{
			"rep":  b,
			"data": *info,
		})
	}
}

func (f *Front) UserList() {
	qu.Catch()
	if f.Method() == "POST" {
		user := f.GetSession("user").(map[string]interface{})
		gid := qu.ObjToString(user["s_groupid"])
		query := map[string]interface{}{"s_groupid": gid, "b_delete": false, "i_state": true, "i_role": "3"}
		field := map[string]interface{}{"s_login": 1, "s_groupid": 1, "s_name": 1}
		info, b := Mgo.Find("s_user", query, nil, field, false, -1, -1)
		if b && len(*info) > 0 {
			f.ServeJson(map[string]interface{}{
				"rep":  b,
				"data": *info,
			})
		}
	}
}

// UserTaskSave 用户任务分发
func (f *Front) UserTaskSave() {
	defer qu.Catch()
	user := f.GetSession("user").(map[string]interface{})
	username := qu.ObjToString(user["s_login"])
	var taskArr []map[string]interface{}
	var userTaskIdArr []string
	userTaskIdInfo := map[string]Task{}
	success := false
	msg := ""
	groupTaskId := f.GetString("grouptaskid") //用户组任务id
	groupTask, _ := Mgo.FindById(TASKCOLLNAME, groupTaskId, nil)
	if len(*groupTask) == 0 {
		qu.Debug("GroupTask Find Error：", groupTaskId)
		msg = "用户组任务：" + groupTaskId + "查询失败"
		f.ServeJson(map[string]interface{}{"success": false, "msg": msg})
		return
	}
	sourceinfo := qu.ObjToString((*groupTask)["s_sourceinfo"])
	userNums := f.GetString("usernums")
	var userArr []map[string]interface{}
	if err := json.Unmarshal([]byte(userNums), &userArr); err != nil {
		qu.Debug("UserInfo Unmarshal Failed：", err)
		msg = "用户信息解析失败"
	} else {
		for _, userInfo := range userArr {
			userid := qu.ObjToString(userInfo["s_userid"])
			name := qu.ObjToString(userInfo["s_name"]) //可能为空
			login := qu.ObjToString(userInfo["s_login"])
			givenum := qu.IntAll(userInfo["i_givenum"])
			userTaskId := primitive.NewObjectID()
			userTaskIdStr := mgo.BsonIdToSId(userTaskId)
			userTaskIdArr = append(userTaskIdArr, userTaskIdStr)
			ut := Task{
				UserId:  userid,
				GiveNum: givenum,
			}
			userTaskIdInfo[userTaskIdStr] = ut
			userTask := map[string]interface{}{
				"_id":           userTaskId,                                    //生成任务id
				"s_projectid":   qu.ObjToString((*groupTask)["s_projectid"]),   //项目标识
				"s_projectname": qu.ObjToString((*groupTask)["s_projectname"]), //项目名称
				"s_status":      "未开始",                                         //任务状态
				"s_personid":    userid,                                        //任务负责人标识
				"s_personname":  name,                                          //任务负责人
				"s_login":       login,                                         //用户账号
				"s_groupname":   qu.ObjToString((*groupTask)["s_groupname"]),   //用户组名称
				"s_groupid":     qu.ObjToString((*groupTask)["s_groupid"]),     //用户组标识
				"i_givenum":     givenum,                                       //分发数据量
				"s_createname":  username,                                      //创建人
				"i_createtime":  time.Now().Unix(),                             //创建时间
				"s_progress":    "0%",                                          //完成进度
				"s_sourceinfo":  sourceinfo,                                    //源数据表
				"s_stype":       "user",                                        //任务类型
				"s_parentid":    groupTaskId,                                   //父任务及用户组任务id
				"s_entname":     qu.ObjToString((*groupTask)["s_entname"]),     //公司名称
				"s_departname":  qu.ObjToString((*groupTask)["s_departname"]),  //部门名称
				"s_rulename":    qu.ObjToString((*groupTask)["s_rulename"]),    //规则名称
			}
			taskArr = append(taskArr, userTask)
		}
	}
	if len(taskArr) > 0 {
		//分发数据后更新对应用户组任务信息
		success = Mgo.UpdateById(TASKCOLLNAME, groupTaskId, map[string]interface{}{
			"$push": map[string]interface{}{
				"v_sonids": map[string]interface{}{
					"$each": userTaskIdArr,
				},
			},
		})
		if !success {
			msg = "更新用户组任务:" + groupTaskId + "关联用户任务失败"
		} else { //用户分发任务
			success = Mgo.SaveBulk(TASKCOLLNAME, taskArr...)
			if success {
				//用户分发任务后更新该用户组任务的状态和开始时间
				Mgo.Update(TASKCOLLNAME,
					map[string]interface{}{
						"_id":      mgo.StringTOBsonId(groupTaskId),
						"s_status": "未开始",
					},
					map[string]interface{}{
						"$set": map[string]interface{}{
							"s_status":    "进行中",
							"i_starttime": time.Now().Unix(),
						}},
					false, false)
				msg = "任务分发成功"
				UpdateSourceInfo(sourceinfo, groupTaskId, userTaskIdInfo) //用户分发任务成功后，同时更新任务数据源表
			}
		}
	}
	f.ServeJson(map[string]interface{}{"success": success, "msg": msg})
}

// UserTaskList 用户任务分发列表
func (f *Front) UserTaskList() {
	defer qu.Catch()
	//groupId := f.GetString("s_groupid") //用户组id
	groupTaskId := f.GetString("grouptaskid") //用户组任务id
	qu.Debug("groupTaskId：", groupTaskId)
	if f.Method() == "POST" {
		start, _ := f.GetInteger("start")
		limit, _ := f.GetInteger("length")
		draw, _ := f.GetInteger("draw")
		status := f.GetString("s_status")
		login := f.GetString("s_login")
		//searchStr := f.GetString("search[value]")
		//search := strings.TrimSpace(searchStr)
		query := map[string]interface{}{
			"s_stype":    "user",
			"s_parentid": groupTaskId,
		}
		if status != "-1" { //任务状态
			query["s_status"] = status
		}
		if login != "-1" { //用户账号
			query["s_login"] = login
		}
		qu.Debug("Query：", query)
		count := Mgo.Count(TASKCOLLNAME, query)
		list, _ := Mgo.Find(TASKCOLLNAME, query, nil, nil, false, start, limit)
		for _, l := range *list {
			if status := qu.ObjToString(l["s_status"]); status == "进行中" { //更新任务进度
				personid := qu.ObjToString(l["s_personid"])
				giveNum := qu.IntAll(l["i_givenum"])
				sourceinfo := qu.ObjToString(l["s_sourceinfo"])
				tagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_userid": personid, "b_istag": true})
				progress := fmt.Sprint(math.Ceil(float64(tagNum)/float64(giveNum))*100) + "%"
				l["s_progress"] = progress
				//同步数据库
				Mgo.UpdateById(TASKCOLLNAME, l["_id"], map[string]interface{}{"$set": map[string]interface{}{"s_progress": progress}})
			}
		}
		f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
	} else {
		sourceinfo := f.GetString("s_sourceinfo")
		qu.Debug(sourceinfo)
		//统计数据量
		isGiveNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": true})     //已分发量
		isNotGiveNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": false}) //待分发量
		isTagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_istag": true})           //已标注数量
		isNotTagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_istag": false})       //未标注数量
		allNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId})                              //数据总量
		qu.Debug("数据总量：", allNum, "已分发量：", isGiveNum, "待分发量：", isNotGiveNum, "已标注量：", isTagNum, "未标注量：", isNotTagNum)
		f.T["grouptaskid"] = groupTaskId
		f.T["allNum"] = allNum
		f.T["isGiveNum"] = isGiveNum
		f.T["isNotGiveNum"] = isNotGiveNum
		f.T["isTagNum"] = isTagNum
		f.T["isNotTagNum"] = isNotTagNum
		_ = f.Render("project/task_detail.html", &f.T)
	}
}

// UserTaskRetrieve 用户任务收回
func (f *Front) UserTaskRetrieve() {
	defer qu.Catch()
	user := f.GetSession("user").(map[string]interface{})
	username := qu.ObjToString(user["s_login"])
	userTaskId := f.GetString("taskid")               //用户任务id
	sourceTaskInfo := f.GetString("s_sourcetaskinfo") //临时表
	msg, count, success := RetrieveTaskByUser(sourceTaskInfo, username, userTaskId)
	//userTask, _ := Mgo.FindById(TASKCOLLNAME, userTaskId, nil)
	f.ServeJson(map[string]interface{}{"success": success, "count": count, "msg": msg})
}

// UpdateSourceInfo 用户分发任务成功后更新数据源表
func UpdateSourceInfo(sourceinfo, groupTaskId string, userTaskIdInfo map[string]Task) {
	defer qu.Catch()
	for userTaskId, tInfo := range userTaskIdInfo {
		userId := tInfo.UserId
		num := tInfo.GiveNum
		sess := Mgo.GetMgoConn()
		defer Mgo.DestoryMongoConn(sess)
		ch := make(chan bool, 5)
		wg := &sync.WaitGroup{}
		lock := &sync.Mutex{}
		query := map[string]interface{}{
			"s_grouptaskid": groupTaskId,
			"b_isgiveuser":  false,
		}
		updateArr := [][]map[string]interface{}{}
		qu.Debug("Query：", query)
		it := sess.DB(Mgo.DbName).C(sourceinfo).Find(&query).Limit(int64(num)).Iter()
		n := 0
		for tmp := make(map[string]interface{}); it.Next(tmp); n++ {
			ch <- true
			wg.Add(1)
			go func(tmp map[string]interface{}) {
				defer func() {
					<-ch
					wg.Done()
				}()
				update := []map[string]interface{}{}
				update = append(update, map[string]interface{}{"_id": tmp["_id"]})
				update = append(update, map[string]interface{}{
					"$set": map[string]interface{}{
						"s_usertaskid": userTaskId,
						"s_userid":     userId,
						"b_isgiveuser": true,
						"i_updatetime": time.Now().Unix(),
					},
				})
				lock.Lock()
				updateArr = append(updateArr, update)
				if len(updateArr) > 500 {
					Mgo.UpdateBulk(sourceinfo, updateArr...)
					updateArr = [][]map[string]interface{}{}
				}
				lock.Unlock()
			}(tmp)
			if n%100 == 0 {
				qu.Debug("current:", n)
			}
			tmp = map[string]interface{}{}
		}
		wg.Wait()
		lock.Lock()
		if len(updateArr) > 0 {
			Mgo.UpdateBulk(sourceinfo, updateArr...)
			updateArr = [][]map[string]interface{}{}
		}
		lock.Unlock()
	}
}

// RetrieveTaskByUser 用户收回任务
func RetrieveTaskByUser(sourceTaskInfo, username string, userTaskIds ...string) (allMsg string, allCount int, allSuccess bool) {
	defer qu.Catch()
	allSuccess = true
	for _, taskId := range userTaskIds {
		query := map[string]interface{}{
			"s_usertaskid": taskId,
			"b_isgiveuser": true,
			"b_iscomplete": false,
		}
		count := Mgo.Count(sourceTaskInfo, query)
		success := false
		qu.Debug("Find Task Id：", taskId, " Retrieve Count：", count)
		if count > 0 {
			set := map[string]interface{}{
				"b_isgiveuser": false,
				"i_updatetime": time.Now().Unix(),
			}
			unset := map[string]interface{}{
				"s_usertaskid": "",
				"s_userid":     "",
			}
			success = Mgo.Update(sourceTaskInfo, query, map[string]interface{}{"$set": set, "$unset": unset}, false, false)
			qu.Debug("User Task", taskId, "Retrieve Data：", success)
			if success {
				allCount += count
				//收回成功，更新task信息
				Mgo.UpdateById(TASKCOLLNAME, taskId, map[string]interface{}{
					"$set": map[string]interface{}{
						"s_status":       "已完成",
						"i_updatetime":   time.Now().Unix(),
						"s_updateperson": username,
						"s_progress":     "100%",
					},
					"$inc": map[string]interface{}{ //更新数据量
						"i_givenum": -count,
					},
				})
			} else {
				allMsg += "任务ID:" + taskId + "更新失败"
				allSuccess = false
			}
		}
	}
	return
}
