package controller

import (
	"background/utils"
	"bytes"
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/fatih/structs"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/tommy351/gin-sessions"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/smtp"
	"regexp"
	"strconv"
	"strings"
	"time"
	"background/config"
	"background/db"
	"background/logs"
	"background/model"
	"background/redis"
)

type UserController struct {

}

type ReqSendEmailCode struct {
	EmailAdress string `json:"email_address"`
}

type SetUserGroupReq struct {
	Id          int64  `json:"id,omitempty"`
	Description string `json:"description"`
	GroupName   string `json:"group_name"`
	UserIds     []int  `json:"user_ids"`
}
type RespBase struct {
	Msg    string
	Status int
	Data   interface{}
}

func (this *UserController) Auth(c *gin.Context) {
	var resp RespBase
	var statuscode int

	statuscode = 200

	var userinfo map[string]interface{}
	//var userSockToken map[string] interface{}

	defer func() {
		c.JSON(statuscode, resp)
	}()

	socketToken := c.Query("socketToken")
	struserinfo, e := redis.Get(socketToken)

	if e != nil {
		logs.Error(e.Error())
		return
	}

	e = json.Unmarshal([]byte(struserinfo), userinfo)
	if nil != e {
		logs.Error(e.Error())
		return
	}
}

// SetUser godoc
// @Summary SetUser
// @Description set userinfo
// @Accept  json
// @Produce  json
// @Param q query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Router /setUser [get]
func (this *UserController) SetUser(c *gin.Context) {

}
// SetUser godoc
// @Summary SetUser
// @Description set userinfo
// @Accept  json
// @Produce  json
// @Param q query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Router /setUser [get]
func (this *UserController) ModifyPasswd(c *gin.Context) {
	type ReqModifyPasswd struct{
		id int  `json:"id"`
		UserName string `json:"user_name"`
		Password string `json:"password"`
	}
	var req ReqModifyPasswd
	var resp RespBase
	resp.Status = -1
	resp.Msg = "err"

	defer func() {
		c.JSON(200,resp)
	}()

	e := c.BindJSON(&req)
	if nil != e{
		logs.Error(e.Error())
		return
	}
	e = model.ModyfyPassword(req.UserName,req.Password)
	if nil != e{
		logs.Error(e.Error())
		return
	}
	resp.Msg = "OK"
	resp.Status = 0

}
// DelUser godoc
// @Summary Delete a user from database
// @Description you must have a token in your parameter
// @Accept  json
// @Produce  json
// @Param q query string false "name search by q"
// @Success 200 {array} util.RespBase
// @Router /setUser [get]
func (this *UserController) DelUser(c *gin.Context) {

}

func (this *UserController) GetUser(c *gin.Context) {
	var resp RespBase
	resp.Msg = "操作失败"
	resp.Status = 20
	defer func() {
		c.JSON(200, resp)
	}()
	session := sessions.Get(c)
	userinfo := session.Get("")
	if userinfo == nil {
		logs.Error("error could not find key")
		return
	}
	var users map[string]interface{}
	e := json.Unmarshal([]byte(userinfo.(string)), &users)
	if nil != e {
		logs.Error(e.Error())
	}
	delete(users, "socketToken")
	resp.Status = 0
	resp.Msg = "操作成功"
	resp.Data = users
}

// GetUsers godoc
// @Summary GetUsers
// @Description Get all user with query
// @Accept  json
// @Produce  json
// @Param page query int 1 "分页的页数"
// @Param pageSize query int 10 "name search by q"
// @Param displayname query string false "name search by q"
// @Param department_id query string false "name search by q"
// @Param permission_type query string false "name search by q"
// @Router /api/users [get]
func (this *UserController) Users(c *gin.Context) {
	var statuscode int
	var resp RespBase

	resp.Msg = "获取失败"
	resp.Status = 0
	statuscode = 200
	defer func() {
		c.JSON(statuscode, resp)
	}()
	offset := c.Query("offset")
	limit := c.Query("limit")
	ioffset, e := strconv.Atoi(offset)
	if nil != e {
		logs.Error(e.Error())
		return
	}
	ilimit, er := strconv.Atoi(limit)
	if nil != er {
		logs.Error(e.Error())
		return
	}

	dat := map[string]interface{}{}
	users, all := model.GetUsers(int32(ilimit), int32(ioffset), "")
	dat["users"] = users
	dat["all"] = all
	resp.Msg = "OK"
	resp.Data = dat
}

// GetUsers godoc
// @Summary GetUsers
// @Description Get all user with query
// @Accept  json
// @Produce  json
// @Param page query int 1 "分页的页数"
// @Param pageSize query int 10 "name search by q"
// @Param displayname query string false "name search by q"
// @Param department_id query string false "name search by q"
// @Param permission_type query string false "name search by q"
// @Router /api/users [get]
func (this *UserController) SerarchUsers(c *gin.Context) {
	var statuscode int
	var resp RespBase

	resp.Msg = "获取失败"
	resp.Status = 0
	statuscode = 200
	defer func() {
		c.JSON(statuscode, resp)
	}()
	offset := c.Query("offset")
	limit := c.Query("limit")
	username := c.PostForm("username")
	ioffset, e := strconv.Atoi(offset)
	if nil != e {
		logs.Error(e.Error())
		return
	}
	ilimit, er := strconv.Atoi(limit)
	if nil != er {
		logs.Error(e.Error())
		return
	}

	dat := map[string]interface{}{}
	users, all := model.GetUsers(int32(ilimit), int32(ioffset), username)
	dat["users"] = users
	dat["all"] = all
	resp.Msg = "OK"
	resp.Data = dat
}
func CreateVerify(length int32) string {
	strAry := []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
	result := string("")
	for i := int32(0); i < length; i++ {
		x := rand.Intn(len(strAry))
		result += string(strAry[x])
	}
	return result
}

/**
 * 取随机Token
 * @param {Number} length 取Token的长度
 * @return {string} 获取的Token
 */
func createToken(length int32) string {
	strAry := []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_'}
	result := string("")
	for i := int32(0); i < length; i++ {
		x := rand.Intn(len(strAry))
		result += string(strAry[x])
	}
	return result
}

func DefaultOption(c *gin.Context) {
	var resp RespBase

	defer func() {
		c.JSON(204, resp)
	}()
}

// Login godoc
// @Summary Login
// @Description login
// @Accept  json
// @Produce  json
// @Param  logininfo query {object} LoginReq  "登录请求参数"
// @Success 200 {array} util.RespBase
// @Failure 400 {object} util.RespBase
// @Failure 404 {object} util.RespBase
// @Failure 500 {object} util.RespBase
// @Router /api/login [post]
func (this *UserController) Login(c *gin.Context) {
	type LoginReq struct {
		RememberMe int32  `json:"remember_me"`
		UserName   string `json:"user_name"`
		UserPwd    string `json:"user_pwd"`
	}
	var req LoginReq
	statusCode := 200
	var resp RespBase

	defer func() {
		c.JSON(statusCode, resp)
	}()
	e := c.Bind(&req)
	if e != nil {
		log.Println(e.Error())
		return
	}

	h := md5.New()
	h.Write([]byte(req.UserPwd)) // 需要加密的字符串为 123456
	passmd5 := h.Sum(nil)
	var result []model.Users
	query := fmt.Sprintf("select * from users where user_name = '%s'",req.UserName)
	er := db.GetMysqlClient().Query2(query,
		&result)
	logs.Debug("sql query:" + query)
	if nil != er {
		log.Println(er.Error())
	}
	strpassmd5 := utils.ByteSliceToString(passmd5)
	if len(result) == 1 {
		if result[0].UserPwd == strpassmd5 {
			socketToken := md5.New()
			socketToken.Write([]byte(createToken(6))) // 需要加密的字符串为 123456
			socketTokenMd5 := socketToken.Sum(nil)
			m := structs.Map(result[0])
			m["SocketToken"] = utils.ByteSliceToString(socketTokenMd5)
			sessionInfo, err := json.Marshal(m)
			if err != nil {
				log.Println(err.Error())
			}
			if req.RememberMe == 1 {
				config.RedisOne().Set(utils.ByteSliceToString(socketTokenMd5), string(sessionInfo), time.Second*2*24*3600*1000)
			} else {
				config.RedisOne().Set(utils.ByteSliceToString(socketTokenMd5), string(sessionInfo), time.Second*8*3600*1000)
			}
			//存储session
			session := sessions.Get(c)
			session.Set("", string(sessionInfo))
			//session.
			var Options *sessions.Options
			if req.RememberMe == 1 {
				Options = &sessions.Options{
					MaxAge: 2 * 24 * 3600 * 1000,
				}
			} else {
				Options = &sessions.Options{
					MaxAge: 8 * 3600 * 1000,
				}
			}
			session.Options(*Options)
			session.Save()

			resp.Msg = "登录成功"
			resp.Status = 0
			resp.Data = string(sessionInfo)
		} else {
			resp.Status = 422
			resp.Msg = "用户密码不正确"
		}
	} else {
		resp.Status = 422
		resp.Msg = "登录账号不存在，请重新输入"
	}
}

func (this *UserController) Register(c *gin.Context) {
	type RegisterReq struct {
		DisplayName string `json:"display_name"`
		EmailAdress string `json:"email_address"`
		EmailCode   string `json:"email_code"`
		UserName    string `json:"user_name"`
		UserPwd     string `json:"user_pwd"`
	}
	var req RegisterReq
	statusCode := 200
	var resp RespBase
	var user model.Users

	resp.Msg = "失败"
	resp.Status = 1

	defer func() {
		c.JSON(statusCode, resp)
	}()

	e := c.Bind(&req)
	if e != nil {
		log.Println(e.Error())
		return
	}
	userKey := fmt.Sprintf("user_%s_verify", req.EmailAdress)
	verify := config.RedisOne().Get(userKey).Val()

	if verify != req.EmailCode {
		resp.Msg = "验证码错误"
		resp.Status = 20
		return
	}

	user.UserName = req.UserName
	user.EmailAddress = req.EmailAdress
	user.DisplayName = req.DisplayName

	h := md5.New()
	h.Write([]byte(req.UserPwd))
	passwdmd5 := h.Sum(nil)
	strpassmd5 := utils.ByteSliceToString(passwdmd5)
	user.UserPwd = strpassmd5
	user.UpdatedDate = time.Now().Format("2006-01-02 15:04:05")
	user.CreatedDate = time.Now().Format("2006-01-02 15:04:05")

	var result []model.Users

	er := db.GetMysqlClient().Query2("select * from users where user_name = ?",
		&result, req.UserName)
	if nil != er {
		log.Println(er.Error())
		return
	}
	if len(result) > 0 {
		resp.Msg = "失败，账号已经存在"
		resp.Status = 20
		return
	}
	query := fmt.Sprintf("insert into users(user_name,user_pwd,created_date,"+
		"updated_date,display_name,email_address) values ('%s','%s','%s','%s','%s','%s')", user.UserName, user.UserPwd, user.CreatedDate, user.UpdatedDate,
		user.DisplayName, user.EmailAddress)
	n, er := db.GetMysqlClient().Insert(query)
	if n == 0 || n < 0 {
		statusCode = 422
		logs.Error(er.Error())
		resp.Msg = "失败，账号已经存在"
		resp.Status = 20
		return
	}
	if nil != er {
		statusCode = 422
		logs.Error(er.Error())
		resp.Msg = "失败"
		resp.Status = 20
		return
	}
	resp.Msg = "成功"
	resp.Status = 0
}

func (this *UserController) Logout(c *gin.Context) {
	var resp RespBase

	resp.Msg = "退出成功"
	resp.Status = 0
	defer func() {
		c.JSON(200, resp)
	}()
	session := sessions.Get(c)
	session.Delete("")
	session.Save()
}

func Reader2Json(r io.ReadCloser) string {
	var ret string
	for i := 0; ; i++ {
		s := make([]byte, 10)
		_, e := r.Read(s)
		ret += string(s)
		if e != nil {
			break
		}
	}
	return ret
}

func SendExternalEmail(msg interface{}) error {
	req := make(map[string]interface{}, 1)
	req["type"] = "text"
	req["action"] = "smtp-sys"
	req["apiType"] = "send"

	content, err := json.Marshal(msg)
	if err != nil {
		log.Println(err.Error())
		return errors.New("Json marshal error")
	}
	req["content"] = string(content)

	var buffer bytes.Buffer
	b, e := json.Marshal(req)
	if e != nil {
		log.Println(e.Error())
	}
	buffer.Write(b)
	resp, err := http.Post("http://47.93.230.163:8091/msg/v1/send", "application/json", &buffer)

	if resp.StatusCode != 200 {
		return errors.New("error send emain")
	}
	if err != nil {
		logs.Error("error send email")
		return err
	}
	return nil
}

func SendToMail(title, user string, password string, host string, to string, content string,
	ifgenerate bool) error {
	var content_type string

	hp := strings.Split(host, ":")
	auth := smtp.PlainAuth("", user, password, hp[0])

	content_type = "Content-Type: text/plain" + "; charset=UTF-8"

	msg := []byte("To: " + to + "\r\nFrom: " + user + "\r\nSubject: " + title + "\r\n" +
		content_type + "\r\n\r\n" + content + "\r\n")
	send_to := strings.Split(to, ";")

	//检测是否是邮件地址
	for k, _ := range send_to {
		match, _ := regexp.MatchString("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?", send_to[k])
		if !match {
			return errors.New("Format Error")
		}
	}
	err := smtp.SendMail(host, auth, user, send_to, msg)
	if err != nil {
		return err
	}
	return err
}

func (this *UserController) SendEmailCode(c *gin.Context) {
	var req ReqSendEmailCode
	var resp RespBase = RespBase{Msg: "邮件已经存在", Status: 0}
	statusCode := 200

	defer func() {
		c.JSON(statusCode, resp)
	}()

	e := c.Bind(&req)
	if nil != e {
		log.Println(e.Error())
		resp.Msg = "请求参数错误"
		return
	}
	//判断邮箱是否存在
	var users []model.Users
	e = db.GetMysqlClient().Query2("select * from users where email_adress = ?", &users, req.EmailAdress)
	if nil != e {
		log.Print(e.Error())
		resp.Msg = "email address error"
		return
	}
	if len(users) != 0 {
		statusCode = 422
		return
	}
	//产生验证码
	verify := CreateVerify(6)
	session := sessions.Get(c)
	session.Set(req.EmailAdress, verify)

	session.Save()
	sendcontent := make(map[string]interface{}, 1)
	sendcontent["subject"] = "邮箱验证码，请注意查收"
	sendcontent["receivers"] = req.EmailAdress
	sendcontent["content"] = string("您本次注册的验证码为:") + verify + string("，工作人员不会向您索取，请勿泄露。请尽快完成操作。")

	e = SendExternalEmail(sendcontent)
	if e != nil {
		log.Println(e.Error())
		return
	}
	//成功
	resp.Msg = "发送成功"
}
