package user

import (
	"bufio"
	"errors"
	"eta/eta_mini_ht_api/common/component/config"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/contants"
	"eta/eta_mini_ht_api/common/exception"
	authUtils "eta/eta_mini_ht_api/common/utils/auth"
	"eta/eta_mini_ht_api/controllers"
	"eta/eta_mini_ht_api/service/auth"
	"eta/eta_mini_ht_api/service/user"
	"os"
	"strings"
)

type AuthController struct {
	controllers.BaseController
}

const ChinaAreaCode = "+86"

// LoginReq  获取验证码请求
type LoginReq struct {
	VerifyCode string `json:"verifyCode"`
	Mobile     string `json:"mobile"`
	AreaCode   string `json:"areaCode"`
}

// Logout 小程序退出登录接口
// @Summary 小程序退出登录接口
// @Description 用户小程序退出登录
// @Param   mobile     body    LoginReq  true        "登录请求体"
// @Success 200 {object} controllers.BaseResponse
// @router /logout [post]
func (a *AuthController) Logout() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("退出登录失败")
		userInfo := a.Data["user"].(user.User)
		err = auth.Logout(userInfo.Id, userInfo.OpenId)
		if err != nil {
			a.FailedResult("退出登录失败", result)
			return
		}
		a.SuccessResult("退出登录成功", nil, result)
		return
	})
}

// Login 小程序登录接口
// @Summary 小程序用户登录
// @Description 用户通过微信小程序登录
// @Param   mobile     body    LoginReq  true        "登录请求体"
// @Success 200 {object} controllers.BaseResponse
// @router /login [post]
func (a *AuthController) Login() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("登录失败")
		loginReq := new(LoginReq)
		a.GetPostParams(loginReq)
		userInfo := a.Data["user"].(user.User)
		if userInfo.Mobile != "" && userInfo.Mobile != loginReq.Mobile {
			a.FailedResult("登录失败,已绑定手机号:"+userInfo.Mobile, result)
			err = exception.New(exception.IllegalAreaCode)
			return
		}
		mobileUser, err := user.GetUserByMobile(loginReq.Mobile)
		if err != nil {
			var etaErr *exception.EtaError
			errors.As(err, &etaErr)
			if etaErr.ErrorCode != exception.TemplateUserNotFound {
				a.FailedResult("登录失败:"+userInfo.Mobile, result)
				err = exception.New(exception.UnknownError)
				return
			}
		}
		if mobileUser.Id > 0 && (mobileUser.Id != userInfo.Id && mobileUser.Mobile == loginReq.Mobile) {
			a.FailedResult("登录失败,该手机号已绑定过微信", result)
			err = exception.New(exception.IllegalAreaCode)
			return
		}
		if loginReq.AreaCode == "" || !checkValidAreaCode(loginReq.AreaCode) {
			a.FailedResult("非法的手机区号", result)
			err = exception.New(exception.IllegalAreaCode)
			return
		}
		if loginReq.AreaCode == ChinaAreaCode && !authUtils.IsValidMobile(loginReq.Mobile) {
			a.FailedResult("只支持86的区号", result)
			err = exception.New(exception.IllegalPhoneNumber)
			return
		}
		err = auth.CheckUser(loginReq.Mobile, loginReq.VerifyCode)
		if err != nil {
			a.FailedResult("验证码错误", result)
			logger.Warn("验证码校验失败:%v", err)
			return
		}
		//用户手机为空需要绑定手机
		if userInfo.Mobile == "" {
			//注册用户或者登录
			err = auth.BindMobile(userInfo.Id, loginReq.Mobile, loginReq.AreaCode)
			if err != nil {
				a.FailedResult("登录异常,绑定手机失败", result)
				return
			}
		}
		//生成一个正式的登录token,生成登录流水
		token, err := auth.Login(userInfo.Id, userInfo.OpenId, loginReq.Mobile, loginReq.VerifyCode)
		if err != nil {
			a.FailedResult("登录异常,生成accessToken失败", result)
			return
		}
		//财人汇判断是否是存量客户

		a.SuccessResult("登录成功", &LoginResp{
			Token: token,
		}, result)
		return
	})
}

type LoginResp struct {
	Token string
}

// SmsCodeReq 获取验证码请求
type SmsCodeReq struct {
	Mobile   string `json:"mobile"`
	AreaCode string `json:"areaCode"`
}

// SMSCode 小程序手机验证码接口
// @Summary 获取手机验证码
// @Param   mobile   body    SmsCodeReq  true        "小程序手机验证码接口"
// @Success 200 {object} controllers.BaseResponse
// @Description 用户发送手机验证码
// @router /sendCode [post]
func (a *AuthController) SMSCode() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("发送短信失败")
		mobile := new(SmsCodeReq)
		a.GetPostParams(mobile)
		if mobile.AreaCode == "" || !checkValidAreaCode(mobile.AreaCode) {
			a.FailedResult("发送短信失败", result)
			err = exception.New(exception.IllegalAreaCode)
			return
		}
		phoneNum := mobile.Mobile
		if mobile.AreaCode == ChinaAreaCode && !authUtils.IsValidMobile(phoneNum) {
			return result, exception.New(exception.IllegalPhoneNumber)
		}
		//发送短息
		err = auth.SendSMSCode(phoneNum)
		if err != nil {
			logger.Warn("发送短信失败:%v", err)
			return result, err
		}
		if err != nil {
			return result, err
		}
		result = &controllers.WrapData{Msg: "验证码发送成功"}
		return result, nil
	})
}

type RefreshTokenRes struct {
	Token        string `json:"token"`
	Status       string `json:"status"`
	IsBindMobile int    `json:"isBindMobile"`
	TokenType    string `json:"tokenType"`
}

// RefreshToken 更新token
// @Summary 更新token
// @Success 200 {object} controllers.BaseResponse
// @Description 更新token
// @router /refreshToken [get]
func (a *AuthController) RefreshToken(code string) {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("刷新token失败")
		if code == "" {
			logger.Error("code不能为空")
			return result, exception.New(exception.WeChatCodeEmpty)
		}
		//刷新token
		token, isBindMobile, status, tokenType, err := auth.RefreshToken(code)
		if err != nil {
			logger.Error("刷新token失败:%v", err)
			a.FailedResult("刷新token失败", result)
			return
		}
		a.SuccessResult("刷新token成功", RefreshTokenRes{
			Token:        token,
			IsBindMobile: isBindMobile,
			TokenType:    tokenType,
			Status:       status,
		}, result)
		return
	})
}

// AreaCodes 小程序手机验证码接口
// @Summary 获取手机验证码
// @Param   mobile   body    SmsCodeReq  true        "小程序手机验证码接口"
// @Success 200 {object} controllers.BaseResponse
// @Description 用户发送手机验证码
// @router /areaCodes [get]
func (a *AuthController) AreaCodes() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("获取区号失败")
		list, err := auth.GetAreaCodes()
		if err != nil {
			a.FailedResult("获取区号失败", result)
		}
		a.SuccessResult("获取区号成功", list, result)
		return
	})
}

type WXAppidResp struct {
	AppId string
}

// WXAppid 获取APPID
// @Summary 获取APPID
// @Success 200 {object} controllers.BaseResponse
// @Description 获取APPID
// @router /wxAppid [get]
func (a *AuthController) WXAppid() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("获取AppId失败")
		appid := config.GetConfig(contants.WECHAT).(*config.WechatConfig).GetAppid()
		if err != nil {
			a.FailedResult("获取AppId失败", result)
		}
		a.SuccessResult("获取AppId成功", WXAppidResp{
			AppId: appid,
		}, result)
		return
	})
}

type FileResp struct {
	Content string
}

// Notice 获取注册须知
// @Summary 获取注册须知
// @Success 200 {object} controllers.BaseResponse
// @Description 获取注册须知
// @router /notice [get]
func (a *AuthController) Notice() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("获取注册须知失败")
		fileConfig := config.GetConfig(contants.FILE).(*config.FileConfig)
		//publicKey := config.GetConfig(contants.FILE).(*config.FileConfig).GetPublicKey()
		noticeFile := fileConfig.GetNotice()
		content, err := readTextConfig(noticeFile)
		if err != nil {
			err = exception.New(exception.GetNoticeFileError)
			a.FailedResult("获取注册须知失败", result)
		}
		a.SuccessResult("获取注册须知成功", FileResp{
			Content: content,
		}, result)
		return
	})
}

// Disclaimer 获取免责声明
// @Summary 获取免责声明
// @Success 200 {object} controllers.BaseResponse
// @Description 获取免责声明
// @router /disclaimer [get]
func (a *AuthController) Disclaimer() {
	controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) {
		result = a.InitWrapData("获取免责声明失败")
		fileConfig := config.GetConfig(contants.FILE).(*config.FileConfig)
		//publicKey := config.GetConfig(contants.FILE).(*config.FileConfig).GetPublicKey()
		disclaimerFile := fileConfig.GetDisclaimer()
		content, err := readTextConfig(disclaimerFile)
		if err != nil {
			a.FailedResult("获取免责声明失败", result)
		}
		a.SuccessResult("获取免责声明成功", FileResp{
			Content: content,
		}, result)
		return
	})
}

// 读取纯文本文件
func readTextConfig(filename string) (content string, err error) {
	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanLines)
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	err = scanner.Err()
	return strings.Join(lines, "\n"), nil
}

func checkValidAreaCode(areaCode string) bool {
	list := auth.GetValidAreaCodes()
	if areaCode == "" || len(list) == 0 {
		return false
	}
	for _, code := range list {
		if areaCode == code {
			return true
		}
	}
	return false
}