package mob

import (
	"applet/app/db"
	"applet/app/e"
	"applet/app/lib/sms"
	"applet/app/lib/zhimeng"
	"applet/app/utils"
	"applet/app/utils/logx"
	"bytes"
	"crypto/cipher"
	"crypto/des"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidwall/gjson"
)

const base string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// Mob is mob sdk
var Mob *SDK

// MobMap is 每个站长都要有自己的mob 对象
var MobMap map[string]*SDK

//Init 初始化
func Init() {
	// 后续可能要传请求的上下文来获取对应的配置
	// mob 目前都是我们来管理每个站长的app 所以使用template 库
	//fmt.Println("Mob SDK init ....")
	ch := make(chan struct{}) // 只是做信号标志的话 空struct 更省点资源
	MobMap = make(map[string]*SDK)
	// 初始化
	for k, e := range db.DBs {
		m := db.SysCfgGetWithDb(e, k, "third_app_push_set")
		if m == "" {
			fmt.Printf("masterid:%s 找不到推送配置", k)
			continue
		}
		key := gjson.Get(m, "mobAppKey").String()
		secret := gjson.Get(m, "mobAppSecret").String()
		if key == "" || secret == "" {
			fmt.Println(k + ":mob no config")
			continue
		}
		// fmt.Println(k, key, secret)
		mob := new(SDK)
		mob.AppKey = key
		mob.AppSecret = secret
		MobMap[k] = mob
		fmt.Println(k + ":mob config success")
	}
	go func() {
		ch <- struct{}{}
	}()

	// 定时任务
	go func(MobMap map[string]*SDK, ch chan struct{}) {
		<-ch
		ticker := time.NewTicker(time.Duration(time.Second * 15))
		//每 15s 一次更新一次mob 配置
		for range ticker.C {
			for k, e := range db.DBs {
				if err := e.Ping(); err != nil {
					logx.Info(err)
					continue
				}
				m := db.SysCfgGetWithDb(e, k, "third_app_push_set")
				if m == "" {
					fmt.Printf("masterid:%s 找不到推送配置", k)
					continue
				}
				key := gjson.Get(m, "mobAppKey").String()
				secret := gjson.Get(m, "mobAppSecret").String()
				if key == "" || secret == "" {
					fmt.Println(k + ":mob no config")
					continue
				}
				// fmt.Println(k, key, secret)
				mob := new(SDK)
				mob.AppKey = key
				mob.AppSecret = secret
				MobMap[k] = mob
				// fmt.Println(k + ":mob config success")
			}
		}
	}(MobMap, ch)
}

// GetMobSDK is 获取mob 的sdk
func GetMobSDK(mid string) (*SDK, error) {
	selectDB := db.DBs[mid]
	m := db.SysCfgGetWithDb(selectDB, mid, "third_app_push_set")
	if m == "" {
		return nil, errors.New("获取不到推送配置")
	}
	key := gjson.Get(m, "mobAppKey").String()
	secret := gjson.Get(m, "mobAppSecret").String()
	if key == "" || secret == "" {
		return nil, fmt.Errorf("%s mob not config", mid)
	}

	return &SDK{AppKey: key, AppSecret: secret}, nil
}

// SDK is mob_push 的sdk
type SDK struct {
	AppKey    string
	AppSecret string
}

//MobFreeLogin is 秒验
func (s *SDK) MobFreeLogin(args map[string]interface{}) (string, error) {
	var url string = "http://identify.verify.mob.com/auth/auth/sdkClientFreeLogin"
	// https://www.mob.com/wiki/detailed/?wiki=miaoyan_for_fuwuduan_mianmifuwuduanjieru&id=78
	//加appkey
	args["appkey"] = s.AppKey
	//加签名
	args["sign"] = generateSign(args, s.AppSecret)
	b, err := json.Marshal(args)
	if err != nil {
		return "", logx.Warn(err)
	}
	// 发送请求
	respBody, err := httpPostBody(url, b)
	if err != nil {
		return "", logx.Warn(err)
	}
	// 反序列化
	ret := struct {
		Status int         `json:"status"`
		Error  string      `json:"error"`
		Res    interface{} `json:"res"`
	}{}
	// 要拿 ret 里面 Res 再解密
	if err := json.Unmarshal(respBody, &ret); err != nil {
		return "", logx.Warn(err)
	}
	//fmt.Println(ret)
	// ret里面的Res 反序列化为结构体
	res := struct {
		IsValid int    `json:"isValid"`
		Phone   string `json:"phone"`
	}{}
	// 判断是否返回正确 状态码
	if ret.Status == 200 {
		decode, _ := base64Decode([]byte(ret.Res.(string)))
		decr, _ := desDecrypt(decode, []byte(s.AppSecret)[0:8])
		if err := json.Unmarshal(decr, &res); err != nil {
			return "", logx.Warn(err)
		}
	}
	// 有效则拿出res 里的电话号码
	if res.IsValid == 1 {
		return res.Phone, nil
	}
	// Status 不等于200 则返回空
	return "", fmt.Errorf("Mob error , status code %v ", ret.Status)
}

// MobSMS is mob 的短信验证
func (s *SDK) MobSMS(c *gin.Context, args map[string]interface{}) (bool, error) {
	// mob 的短信验证
	// https://www.mob.com/wiki/detailed/?wiki=SMSSDK_for_yanzhengmafuwuduanxiaoyanjiekou&id=23
	url := "https://webapi.sms.mob.com/sms/verify"
	//加appkey
	args["appkey"] = s.AppKey
	fmt.Println(args)
	//fmt.Println(args)
	// 发送请求
	respBody, err := utils.CurlPost(url, args, nil)
	if err != nil {
		fmt.Println(err)
		return false, logx.Warn(err)
	}
	fmt.Println("=======================mob")
	fmt.Println("mob", string(respBody))
	code := gjson.GetBytes(respBody, "status").Int()
	if code == 468 {
		return false, errors.New("验证码错误")
	}
	if code != 200 {
		utils.FilePutContents("sms", string(respBody))
		return false, errors.New("验证码错误~")
	}

	if c.GetString("not_deduction_doing") == "1" { //这是前面扣过了
		return true, nil
	}
	// TODO 成功后扣费暂时先接旧智盟
	sdk, err := sms.NewZhimengSMS(c).SelectFunction("deduction_doing").WithSMSArgs(map[string]interface{}{
		"mobile": args["phone"],
		"getmsg": "1",
	}).Result()
	if err != nil {
		return false, logx.Warn(err)
	}
	zr := sdk.ToInterface().(string)
	if zr == "1" {
		logx.Infof("旧智盟扣费成功 appkey %s", zhimeng.SMS_APP_KEY)
	}
	return true, nil
}

func pkcs5UnPadding(origData []byte) []byte {
	length := len(origData)
	// 去掉最后一个字节 unpadding 次
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func desDecrypt(crypted, key []byte) ([]byte, error) {
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockMode := cipher.NewCBCDecrypter(block, []byte("00000000"))
	origData := make([]byte, len(crypted))
	// origData := crypted
	blockMode.CryptBlocks(origData, crypted)
	origData = pkcs5UnPadding(origData)
	// origData = ZeroUnPadding(origData)
	return origData, nil
}

func base64Decode(src []byte) ([]byte, error) {
	var coder *base64.Encoding
	coder = base64.NewEncoding(base)
	return coder.DecodeString(string(src))
}

func httpPostBody(url string, msg []byte) ([]byte, error) {
	resp, err := http.Post(url, "application/json;charset=utf-8", bytes.NewBuffer(msg))
	if err != nil {
		return []byte(""), err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}

func generateSign(request map[string]interface{}, secret string) string {
	ret := ""
	var keys []string
	for k := range request {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		ret = ret + fmt.Sprintf("%v=%v&", k, request[k])
	}
	ret = ret[:len(ret)-1] + secret

	md5Ctx := md5.New()
	md5Ctx.Write([]byte(ret))
	cipherStr := md5Ctx.Sum(nil)
	return hex.EncodeToString(cipherStr)
}

func Check(c *gin.Context, phone, zone, validCode string, ok1 bool) (bool, error) {
	smsPlatform := sms.GetSmsPlatform(c)

	if smsPlatform == "mob" {
		mob1, errr := GetMobSDK(c.GetString("mid"))
		if errr != nil {
			return false, e.NewErr(400, "mob配置错误")
		}
		send := map[string]interface{}{
			"phone": phone,
			"zone":  zone,
			"code":  validCode,
		}
		if zone == "" {
			send["zone"] = "86"
		}
		c.Set("not_deduction_doing", "1")
		ok, err := mob1.MobSMS(c, send)
		fmt.Println(ok)
		if err != nil {
			fmt.Println(err)
			return false, e.NewErr(400, "验证码校验错误")
		}

		return ok, nil
	}
	return ok1, nil
}
