package controllers

import (
	"encoding/json"
	"fmt"
	"github.com/medivhzhan/weapp/v2"
	"hongze/hongze_cygx/models"
	"hongze/hongze_cygx/services"
	"hongze/hongze_cygx/utils"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type WechatController struct {
	BaseAuthController
}

type WechatCommonController struct {
	BaseCommonController
}

// @Title 微信登录接口
// @Description 微信登录接口
// @Param   Code   query   string  true       "微信唯一编码code"
// @Success 200 {object} models.WxLoginResp
// @router /login [get]
func (this *WechatCommonController) WechatLogin() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	code := this.GetString("Code")
	if code == "" {
		br.Msg = "参数错误"
		br.ErrMsg = "Code 为空"
		return
	}
	wxInfo, err := weapp.Login(utils.WxAppId, utils.WxAppSecret, code)
	if err != nil {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取用户信息失败,Err:" + err.Error()
		return
	}
	if err = wxInfo.GetResponseError(); err != nil {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取用户信息失败,code:" + strconv.Itoa(wxInfo.ErrCode) + ",msg:" + wxInfo.ErrMSG
		return
	}

	wxUserInfo := new(services.WxUserInfo)
	wxUserInfo.Unionid = wxInfo.UnionID
	wxUserInfo.Openid = wxInfo.OpenID
	wxUserInfo.Errcode = wxInfo.ErrCode
	wxUserInfo.Errmsg = wxInfo.ErrMSG
	wxUserInfo.SessionKey = wxInfo.SessionKey
	token, userId, firstLogin, _, err := services.WxLogin(code, wxInfo.OpenID, wxInfo.UnionID, wxUserInfo)
	if err != nil && err.Error() != utils.ErrNoRow() {
		br.Msg = "微信登录失败"
		br.ErrMsg = "微信登录失败,err:" + err.Error()
		return
	}
	if token == "" {
		br.Msg = "微信登录失败"
		br.ErrMsg = "token:" + token + "" + code + " " + wxInfo.OpenID + " " + wxInfo.UnionID
		return
	}
	//新增登录日志
	{
		loginLog := new(models.WxUserLog)
		loginLog.UserId = userId
		loginLog.OpenId = wxInfo.OpenID
		loginLog.UnionId = wxInfo.UnionID
		loginLog.CreateTime = time.Now()
		loginLog.Handle = "wechat_login_cygx"
		loginLog.Remark = token
		go models.AddWxUserLog(loginLog)
	}
	{
		codeLog := new(models.WxUserCode)
		codeLog.WxCode = code
		codeLog.UserId = userId
		codeLog.Code = 0
		codeLog.FirstLogin = firstLogin
		codeLog.Authorization = token
		codeLog.UserPermission = 1
		codeLog.CreateTime = time.Now()
		models.AddWxUserCode(codeLog)
	}

	resp := new(models.WxLoginResp)
	resp.UserId = userId
	resp.FirstLogin = firstLogin
	resp.Authorization = token
	br.Ret = 200
	br.Success = true
	br.Msg = "登录成功"
	br.Data = resp
}

// @Title 小程序获取用户信息
// @Description 小程序获取用户信息接口(需要登录)
// @Param	request	body models.WxGetUserInfoReq true "type json string"
// @Success 200 {object} models.WxGetUserInfoResp
// @router /getUserInfo [post]
func (this *WechatController) GetUserInfo() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	var req models.WxGetUserInfoReq
	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
	if err != nil {
		br.Msg = "参数解析异常!"
		br.ErrMsg = "参数解析失败,Err:" + err.Error()
		return
	}
	if req.RawData == "" || req.EncryptedData == "" || req.Signature == "" || req.Iv == "" {
		br.Msg = "参数错误"
		return
	}
	user := this.User
	if user == nil {
		br.Msg = "请登陆"
		br.Ret = 408
		return
	}
	userId := user.UserId
	sessionKey := user.SessionKey
	fmt.Println("sessionKey:", sessionKey)
	fmt.Println(sessionKey, req.RawData, req.EncryptedData, req.Signature, req.Iv)
	userInfo, err := weapp.DecryptUserInfo(sessionKey, req.RawData, req.EncryptedData, req.Signature, req.Iv)
	fmt.Println("weapp.DecryptUserInfo ", err)

	if err != nil {
		br.Msg = "解析用户信息失败"
		br.ErrMsg = "解析用户信息失败,DecryptUserInfo Err:" + err.Error()
		return
	}
	//修改用户微信信息
	err = models.ModifyUserRecordByDetail(userInfo.OpenID, userInfo.UnionID, userInfo.Nickname, userInfo.Avatar, userInfo.City, userInfo.Province, userInfo.Country, userInfo.Gender, userId)
	if err != nil {
		br.Msg = "授权失败"
		br.ErrMsg = "授权失败,修改用户信息失败:" + err.Error()
		return
	}
	var token string
	tokenItem, err := models.GetTokenByOpenId(userInfo.OpenID)
	if err != nil && err.Error() != utils.ErrNoRow() {
		br.Msg = "授权失败"
		br.ErrMsg = "授权失败,获取token失败:" + err.Error()
		return
	}

	if tokenItem == nil || (err != nil && err.Error() == utils.ErrNoRow()) {
		timeUnix := time.Now().Unix()
		timeUnixStr := strconv.FormatInt(timeUnix, 10)
		token = utils.MD5(userInfo.OpenID) + utils.MD5(timeUnixStr)
		//新增session
		{
			session := new(models.CygxSession)
			session.OpenId = userInfo.OpenID
			session.UnionId = userInfo.UnionID
			session.UserId = userId
			session.CreatedTime = time.Now()
			session.LastUpdatedTime = time.Now()
			session.ExpireTime = time.Now().AddDate(0, 3, 0)
			session.AccessToken = token
			err = models.AddSession(session)
			if err != nil {
				br.Msg = "授权失败"
				br.ErrMsg = "授权失败,新增用户session信息失败:" + err.Error()
				return
			}
		}
	} else {
		token = tokenItem.AccessToken
	}
	resp := new(models.WxGetUserInfoResp)
	resp.Authorization = token
	br.Msg = "获取成功!"
	br.Ret = 200
	br.Success = true
}

// @Title 小程序获取用户绑定手机号
// @Description 小程序获取用户绑定手机号接口(需要登录)
// @Param	request	body models.WxGetPhoneNumberReq true "type json string"
// @Success 200 {object} models.WxGetPhoneNumberResp
// @router /getPhoneNumber [post]
func (this *WechatController) GetPhoneNumber() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	var req models.WxGetPhoneNumberReq
	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
	if err != nil {
		br.Msg = "参数解析异常!"
		br.ErrMsg = "参数解析失败,Err:" + err.Error()
		return
	}
	if req.EncryptedData == "" || req.Iv == "" {
		br.Msg = "参数错误"
		return
	}
	user := this.User
	if user == nil {
		br.Msg = "请登陆"
		br.Ret = 408
		return
	}
	sessionKey := user.SessionKey
	wxMobile, err := weapp.DecryptMobile(sessionKey, req.EncryptedData, req.Iv)
	if err != nil {
		br.Msg = "解析用户手机号信息失败"
		br.ErrMsg = "解析用户手机号信息失败,Err:" + err.Error()
		return
	}
	err = models.ModifyUsersMobile(user.UserId, wxMobile.PurePhoneNumber)
	if err != nil {
		br.Msg = "获取失败"
		br.ErrMsg = "获取失败,Err:" + err.Error()
		return
	}

	resp := new(models.WxGetPhoneNumberResp)
	resp.PhoneNumber = wxMobile.PhoneNumber
	resp.PurePhoneNumber = wxMobile.PurePhoneNumber
	resp.CountryCode = wxMobile.CountryCode
	br.Msg = "获取成功!"
	br.Ret = 200
	br.Success = true
	br.Data = resp
}

// @Title 获取短信验证码
// @Description 获取短信验证码接口
// @Param   Mobile   query   string  true       "手机号码"
// @Param   AreaNum   query   string  true       "地区编码"
// @Success Ret=200 获取成功
// @router /getSmsCode [get]
func (this *WechatController) GetSmsCode() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	mobile := this.GetString("Mobile")
	if mobile == "" {
		br.Msg = "请输入手机号"
		return
	}
	areaNum := this.GetString("AreaNum")
	msgCode := utils.GetRandDigit(4)
	var result bool
	if areaNum == "86" || areaNum == "" || areaNum == "0" {
		result = services.SendSmsCode(mobile, msgCode)
	} else {
		result = services.SendSmsCodeGj(mobile, msgCode, areaNum)
	}
	//发送成功
	if result {
		item := new(models.MsgCode)
		item.OpenId = ""
		item.Code = msgCode
		item.Mobile = mobile
		item.ExpiredIn = time.Now().Add(15 * time.Minute).Unix()
		item.Enabled = 1
		item.CreatedTime = time.Now()
		err := models.AddMsgCode(item)
		if err != nil {
			br.Msg = "发送失败"
			br.ErrMsg = "发送失败,Err:" + err.Error()
			return
		}
		br.Msg = "发送成功"
	} else {
		br.Msg = "发送失败"
	}
	br.Ret = 200
	br.Success = true
}

// @Title 获取邮件验证码
// @Description 获取邮件验证码接口
// @Param   Email   query   string  true       "邮箱"
// @Success Ret=200 获取成功
// @router /getEmailCode [get]
func (this *WechatController) GetEmailCode() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	email := this.GetString("Email")
	if email == "" {
		br.Msg = "请输入邮箱地址"
		return
	}
	if !utils.ValidateEmailFormatat(email) {
		br.Msg = "邮箱格式错误,请重新输入"
		return
	}
	msgCode := utils.GetRandDigit(4)
	content := "尊敬的用户:</br>您好,感谢您使用弘则研究,您正在进行邮箱验证,本次请求的验证码为:" + msgCode + "(为了保障您账号的安全性,请在15分钟内完成验证。)</br>弘则研究团队 </br>2019年05月11日"
	title := "弘则研究登陆验证"
	//发送邮件
	result, err := utils.SendEmailByHz(title, content, email)
	if err != nil {
		br.Msg = "发送失败"
		br.ErrMsg = "发送失败,Err:" + err.Error()
		return
	}
	if result {
		item := new(models.MsgCode)
		item.OpenId = ""
		item.Code = msgCode
		item.Mobile = email
		item.ExpiredIn = time.Now().Add(15 * time.Minute).Unix()
		item.Enabled = 1
		item.CreatedTime = time.Now()
		err := models.AddMsgCode(item)
		if err != nil {
			br.Msg = "发送失败"
			br.ErrMsg = "发送失败,Err:" + err.Error()
			return
		}
		br.Msg = "发送成功"
	} else {
		br.Msg = "发送失败"
	}
	br.Ret = 200
	br.Success = true
}

// @Title 更新微信token
// @Description 更新微信token
// @Success Ret=200 更新成功
// @router /updateWxAccesstoken [get]
func (this *WechatController) UpdateWxAccesstoken() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	accessToken, err := models.GetWxAccessToken()
	if err != nil {
		utils.FileLog.Info("GetWxAccessToken Err:%s", err.Error())
		return
	}
	br.Data = accessToken
	br.Ret = 200
	br.Success = true
}

// @Title 微信登录小助手接口
// @Description 微信登录小助手接口
// @Param   Code   query   string  true       "微信唯一编码code"
// @Success 200 {object} models.WxLoginResp
// @router /loginByxzs [get]
func (this *WechatCommonController) WechatLoginByxzs() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	code := this.GetString("Code")
	if code == "" {
		br.Msg = "参数错误"
		br.ErrMsg = "Code 为空"
		return
	}

	item, err := services.WxGetUserOpenIdByCodeXzs(code)
	if err != nil {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取用户信息失败,Err:" + err.Error()
		return
	}
	if item.Errcode != 0 {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取access_token 失败 errcode:" + strconv.Itoa(item.Errcode) + " ;errmsg:" + item.Errmsg
		return
	}
	openId := item.Openid
	if openId == "" {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取openid失败,openid:" + item.Openid
		return
	}
	unionId := item.Unionid
	if unionId == "" {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "获取unionid失败,unionid:" + item.Openid
		return
	}
	total, err := models.GetCygxUserRecordCount(openId)
	if err != nil {
		br.Msg = "获取用户信息失败"
		br.ErrMsg = "查询数量失败,Err:" + err.Error()
		return
	}
	if total == 0 {
		items := new(models.CygxUserRecord)
		items.OpenId = openId
		items.UnionId = unionId
		items.CreateTime = time.Now()
		_, err = models.AddCygxUserRecord(items)
		if err != nil {
			br.Msg = "获取用户信息失败"
			br.ErrMsg = "添加openid失败,Err:" + err.Error()
			return
		}
	}
	br.Ret = 200
	br.Success = true
	br.Msg = "获取成功"
	br.Data = item
}

// @Title 获取小程序分享二维码
// @Description 获取小程序分享二维码
// @Success 200 {object} models.ArticleDetailFileLink
// @router /shareImage [post]
func (this *WechatController) ShareImage() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	user := this.User
	if user == nil {
		br.Msg = "请登录"
		br.ErrMsg = "请登录,用户信息为空"
		br.Ret = 408
		return
	}
	uid := user.UserId
	itemToken, err := services.WxGetToken()
	if err != nil {
		br.Msg = "分享失败"
		br.ErrMsg = "获取itemToken失败,Err:" + err.Error()
		return
	}
	if itemToken.AccessToken == "" {
		br.Msg = "accessToken is empty"
		return
	}
	var envVersion string
	var resourceUrl string
	if utils.RunMode == "release" {
		envVersion = "release"
	} else {
		envVersion = "develop"
	}
	url := "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + itemToken.AccessToken
	method := "POST"
	payload := strings.NewReader(`{
		"page":"pageMy/excessivePages/excessivePages",
		"scene":"` + strconv.Itoa(uid) + `",
		"env_version":"` + envVersion + `",
		"check_path":false,
		"auto_color":true
				}`)
	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		br.Msg = "分享失败"
		br.ErrMsg = "获取微信二维码失败,Err:" + err.Error()
		return
	}
	req.Header.Add("Content-Type", "application/json")
	postBody, err := client.Do(req)
	if err != nil {
		br.Msg = "分享失败"
		br.ErrMsg = "获取微信二维码失败,Err:" + err.Error()
		return
	}
	defer postBody.Body.Close()
	uploadDir := "static/img/share/"
	uuid := utils.GetRandStringNoSpecialChar(28)
	if !utils.FileIsExist(uploadDir) {
		err = os.MkdirAll(uploadDir, 0755)
		if err != nil {
			br.Msg = "分享失败"
			br.ErrMsg = "生成文件夹失败,Err:" + err.Error()
			return
		}
	}
	imagePath := uploadDir + uuid + ".jpg"
	switch header := postBody.Header.Get("Content-Type"); {
	case strings.HasPrefix(header, "application/json"):
		tokenResp := models.ReturnBodyRule{}
		decoder := json.NewDecoder(postBody.Body)
		if decodeErr := decoder.Decode(&tokenResp); decodeErr != nil {
			br.Msg = "分享失败"
			br.ErrMsg = "获取微信二维码失败,Err:" + decodeErr.Error()
			return
		}
	case strings.HasPrefix(header, "image"):
		reply, err := ioutil.ReadAll(postBody.Body)
		if err != nil {
			br.Msg = "分享失败"
			br.ErrMsg = "获取微信二维码失败,Err:" + err.Error()
			return
		}
		imageContent, createErr := os.Create(imagePath)
		if createErr != nil {
			br.Msg = "分享失败"
			br.ErrMsg = "获取微信二维码失败,Err:" + createErr.Error()
			return
		}
		writeStringRes, writeStringErr := io.WriteString(imageContent, string(reply))
		if writeStringErr != nil {
			fmt.Println(writeStringRes)
			br.Msg = "分享失败"
			br.ErrMsg = "获取微信二维码失败,Err:" + writeStringErr.Error()
			return
		}
		closeErr := imageContent.Close()
		if closeErr != nil {
			br.Msg = "分享失败"
			br.ErrMsg = "获取微信二维码失败,Err:" + closeErr.Error()
			return
		}
		randStr := utils.GetRandStringNoSpecialChar(28)
		fileName := randStr + ".jpg"
		savePath := uploadDir + time.Now().Format("200601/20060102/")
		savePath += fileName
		//上传到阿里云
		err = services.UploadFileToAliyun(fileName, imagePath, savePath)
		if err != nil {
			fmt.Println("文件上传失败,Err:" + err.Error())
			return
		}
		fileHost := "https://hzstatic.hzinsights.com/"
		resourceUrl = fileHost + savePath
		defer func() {
			os.Remove(imagePath)
		}()
	default:
		br.Msg = "分享失败"
		br.ErrMsg = "没有获取到分享二维码"
		return
	}
	resp := new(models.ArticleDetailFileLink)
	resp.FileLink = resourceUrl
	resp.Scene = strconv.Itoa(uid)
	br.Ret = 200
	br.Data = resp
	br.Success = true
	br.Msg = "提交成功"
}

// @Title 获取短信验证码(无需token)
// @Description 获取短信验证码接口(无需token)
// @Param   Mobile   query   string  true       "手机号码"
// @Param   AreaNum   query   string  true       "地区编码"
// @Success Ret=200 获取成功
// @router /getSmsCodePublic [get]
func (this *WechatCommonController) GetSmsCode() {
	br := new(models.BaseResponse).Init()
	defer func() {
		this.Data["json"] = br
		this.ServeJSON()
	}()
	mobile := this.GetString("Mobile")
	if mobile == "" {
		br.Msg = "请输入手机号"
		return
	}
	areaNum := this.GetString("AreaNum")
	msgCode := utils.GetRandDigit(4)
	var result bool
	if areaNum == "86" || areaNum == "" || areaNum == "0" {
		result = services.SendSmsCode(mobile, msgCode)
	} else {
		result = services.SendSmsCodeGj(mobile, msgCode, areaNum)
	}
	//发送成功
	if result {
		item := new(models.MsgCode)
		item.OpenId = ""
		item.Code = msgCode
		item.Mobile = mobile
		item.ExpiredIn = time.Now().Add(15 * time.Minute).Unix()
		item.Enabled = 1
		item.CreatedTime = time.Now()
		err := models.AddMsgCode(item)
		if err != nil {
			br.Msg = "发送失败"
			br.ErrMsg = "发送失败,Err:" + err.Error()
			return
		}
		br.Msg = "发送成功"
	} else {
		br.Msg = "发送失败"
	}
	br.Ret = 200
	br.Success = true
}