package maycur

import (
	"crypto/hmac"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/rdlucklib/rdluck_tools/common"
	"hongze/hz_crm_api/models"
	"hongze/hz_crm_api/services/alarm_msg"
	"hongze/hz_crm_api/utils"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	ShanghaiCRMCompanyListUrl        = `/v2/Customer/basicSaleCustomerRelation`
	ShanghaiCRMSellerListUrl         = `/v2/AdminUser/EquitySaleDeptMemberList`
	ShanghaiCRMCompanyListUrlRelease = `https://crm.hzinsights.com/openapi/v2/Customer/basicSaleCustomerRelation`
	ShanghaiCRMSellerListUrlRelease  = `https://crm.hzinsights.com/openapi/v2/AdminUser/EquitySaleDeptMemberList`
)

// openApiParamsBuild 生成Api参数(含签名)
func openApiParamsBuild(paramMap map[string]string) (params url.Values) {
	// 公共参数
	strRand := utils.GetRandStringNoSpecialChar(32)
	timestamp := fmt.Sprint(time.Now().Unix())
	values := map[string]string{
		"app_key":   utils.CRM_OPEN_API_APP_KEY,
		"nonce_str": strRand,
		"timestamp": timestamp,
	}

	// ASCII排序
	keys := make([]string, 0)
	keys = append(keys, "app_key", "nonce_str", "timestamp")
	for k, v := range paramMap {
		keys = append(keys, k)
		values[k] = v
	}
	sort.Strings(keys)

	params = make(map[string][]string)
	signArr := make([]string, 0) // 参与签名生成的参数
	for _, k := range keys {
		params.Add(k, values[k])
		signArr = append(signArr, fmt.Sprint(k, "=", values[k]))
	}

	// 签名
	strA := strings.Join(signArr, "&")
	h := hmac.New(md5.New, []byte(utils.CRM_OPEN_API_APP_SECRET))
	h.Write([]byte(strA))
	strB := hex.EncodeToString(h.Sum([]byte("")))
	strD := common.UrlEncode(strB)
	params.Add("signature", strD)
	return
}

// PublicOfferingCompanyApiResp 客户列表响应体
type PublicOfferingCompanyApiResp struct {
	Code int    `description:"状态码: 1-成功; 0-失败; >1-指定错误"`
	Msg  string `description:"提示信息"`
	Time int64  `description:"时间戳"`
	Data struct {
		Paginator struct {
			Total       int `description:"数据总量"`
			CurrentPage int `description:"当前页码" json:"current_page"`
			ListRow     int `description:"每页数据量" json:"list_row"`
			LastPage    int `description:"最后一页页码" json:"last_page"`
		} `description:"分页信息"`
		Data []struct {
			Name      string `description:"公司名称"`
			ShortName string `description:"公司简称" json:"short_name"`
			Social    string `description:"公司社会信用码"`
			UserId    string `description:"销售ID" json:"user_id"`
			Username  string `description:"销售名称"`
		} `description:"公司列表"`
	} `description:"响应数据"`
}

// CurlPublicOfferingCompanyApi 请求客户列表接口
func CurlPublicOfferingCompanyApi(strParams string) (body []byte, err error) {
	//curlUrl := fmt.Sprintf("%s%s?%s", utils.CRM_OPEN_API_URL, ShanghaiCRMCompanyListUrl, strParams)
	curlUrl := fmt.Sprintf("%s?%s", ShanghaiCRMCompanyListUrlRelease, strParams)
	res, e := http.Get(curlUrl)
	if e != nil {
		err = fmt.Errorf("http get err: %s", e.Error())
		return
	}
	defer func() {
		_ = res.Body.Close()
	}()
	body, e = ioutil.ReadAll(res.Body)
	if e != nil {
		err = fmt.Errorf("http body err: %s", e.Error())
		return
	}
	//utils.FileLog.Info("open api http resp: %s", string(body))
	return
}

// PublicOfferingSaleApiResp 销售列表响应体
type PublicOfferingSaleApiResp struct {
	Code int    `description:"状态码: 1-成功; 0-失败; >1-指定错误"`
	Msg  string `description:"提示信息"`
	Time int64  `description:"时间戳"`
	Data []struct {
		Mobile   string `description:"手机号"`
		Nickname string `description:"销售姓名"`
		DeptText string `description:"部门描述" json:"dept_text"`
		IsLeader int    `description:"是否为负责人: 0-否; 1-是" json:"is_leader"`
	} `description:"响应数据"`
}

// CurlEquitySaleListApi 请求公募销售列表接口
func CurlEquitySaleListApi(strParams string) (body []byte, err error) {
	//curlUrl := fmt.Sprintf("%s%s?%s", utils.CRM_OPEN_API_URL, ShanghaiCRMSellerListUrl, strParams)
	curlUrl := fmt.Sprintf("%s?%s", ShanghaiCRMSellerListUrlRelease, strParams)
	res, e := http.Get(curlUrl)
	if e != nil {
		err = fmt.Errorf("http get err: %s", e.Error())
		return
	}
	defer func() {
		_ = res.Body.Close()
	}()
	body, e = ioutil.ReadAll(res.Body)
	if e != nil {
		err = fmt.Errorf("http body err: %s", e.Error())
		return
	}
	utils.FileLog.Info("open api http resp: %s", string(body))
	return
}

// SyncPublicOfferingSale 同步公募销售
func SyncPublicOfferingSale() (err error) {
	defer func() {
		if err != nil {
			msg := fmt.Sprintf("每刻-同步公募销售失败, ErrMsg: %s", err.Error())
			utils.FileLog.Error(msg)
			go alarm_msg.SendAlarmMsg(msg, 3)
		}
	}()
	paramMap := make(map[string]string)
	params := openApiParamsBuild(paramMap)
	strParams := params.Encode()
	res, e := CurlEquitySaleListApi(strParams)
	if e != nil {
		err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error())
		return
	}
	if len(res) == 0 {
		err = fmt.Errorf("公募销售数据为空")
		return
	}
	var resp PublicOfferingSaleApiResp
	if e := json.Unmarshal(res, &resp); e != nil {
		err = fmt.Errorf("解析公募销售数据失败, Err: %s; Body: %s", e.Error(), string(res))
		return
	}
	if resp.Code != 1 {
		err = fmt.Errorf("获取公募销售数据失败, Body: %s", string(res))
		return
	}
	sales := resp.Data

	// 去重
	saleOB := new(models.MaycurPublicOfferingSale)
	saleCond := ``
	salePars := make([]interface{}, 0)
	origins, e := saleOB.GetItemsByCondition(saleCond, salePars, []string{}, "")
	if e != nil {
		err = fmt.Errorf("获取公募销售留档失败, Err: %s", e.Error())
		return
	}
	salesNameVal := make(map[string]*models.MaycurPublicOfferingSale)
	for _, s := range origins {
		salesNameVal[s.Nickname] = s
	}
	// 新增
	inserts := make([]*models.MaycurPublicOfferingSale, 0)
	updateCols := []string{"Mobile", "DeptText", "IsLeader", "ModifyTime"}
	for _, v := range sales {
		s := salesNameVal[v.Nickname]
		if s != nil {
			s.Mobile = v.Mobile
			s.DeptText = v.DeptText
			s.IsLeader = v.IsLeader
			s.ModifyTime = time.Now().Local()
			if e = s.Update(updateCols); e != nil {
				err = fmt.Errorf("更新公募销售信息失败, Err: %s", e.Error())
				return
			}
			continue
		}
		inserts = append(inserts, &models.MaycurPublicOfferingSale{
			Mobile:     v.Mobile,
			Nickname:   v.Nickname,
			CreateTime: time.Now().Local(),
			ModifyTime: time.Now().Local(),
		})
	}
	if e = saleOB.CreateMulti(inserts); e != nil {
		err = fmt.Errorf("新增公募销售失败, Err: %s", e.Error())
		return
	}
	return
}

// SyncPublicOfferingCompany 同步客户列表, 过滤出公募客户入库留档
func SyncPublicOfferingCompany() (err error) {
	defer func() {
		if err != nil {
			msg := fmt.Sprintf("每刻-同步公募客户失败, ErrMsg: %s", err.Error())
			utils.FileLog.Error(msg)
			go alarm_msg.SendAlarmMsg(msg, 3)
		}
	}()

	// 去重
	companyOB := new(models.MaycurPublicOfferingCompany)
	companyCond := ``
	companyPars := make([]interface{}, 0)
	origins, e := companyOB.GetItemsByCondition(companyCond, companyPars, []string{}, "")
	if e != nil {
		err = fmt.Errorf("获取公募客户留档失败, Err: %s", e.Error())
		return
	}
	companyCodeVal := make(map[string]*models.MaycurPublicOfferingCompany)
	for _, s := range origins {
		companyCodeVal[s.Social] = s
	}

	// 获取公募销售
	saleOB := new(models.MaycurPublicOfferingSale)
	sales, e := saleOB.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
	if e != nil {
		err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error())
		return
	}
	saleArr := make([]string, 0)
	for _, s := range sales {
		saleArr = append(saleArr, s.Nickname)
	}

	currentPage := 1
	pageSize := 100
	updateCols := []string{"SaleNames", "ModifyTime"}
	codeSales := make(map[string][]string)
	for {
		paramMap := make(map[string]string)
		paramMap["limit"] = strconv.Itoa(pageSize)
		paramMap["f_e"] = "Equity"
		paramMap["page"] = strconv.Itoa(currentPage)
		params := openApiParamsBuild(paramMap)
		strParams := params.Encode()
		res, e := CurlPublicOfferingCompanyApi(strParams)
		if e != nil {
			err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error())
			return
		}
		if len(res) == 0 {
			err = fmt.Errorf("公募销售数据为空")
			return
		}
		var resp PublicOfferingCompanyApiResp
		if e := json.Unmarshal(res, &resp); e != nil {
			err = fmt.Errorf("解析公募客户数据失败, Err: %s; Body: %s", e.Error(), string(res))
			return
		}
		if resp.Code != 1 {
			err = fmt.Errorf("获取公募客户数据失败, Body: %s", string(res))
			return
		}
		data := resp.Data
		companies := data.Data

		codeCompany := make(map[string]*models.MaycurPublicOfferingCompany)
		for _, c := range companies {
			// 过滤测试客户
			if strings.Contains(c.Name, "测试") || strings.Contains(strings.ToLower(c.Name), "test") {
				continue
			}
			// 如果该客户的销售中无公募销售, 则忽略
			if !utils.InArrayByStr(saleArr, c.Username) {
				continue
			}

			if codeCompany[c.Social] == nil {
				v := &models.MaycurPublicOfferingCompany{
					Name:       c.Name,
					ShortName:  c.ShortName,
					Social:     c.Social,
					CreateTime: time.Now().Local(),
					ModifyTime: time.Now().Local(),
				}
				codeCompany[c.Social] = v
			}
			if c.Username != "" && !utils.InArrayByStr(codeSales[c.Social], c.Username) {
				codeSales[c.Social] = append(codeSales[c.Social], c.Username)
			}
		}
		inserts := make([]*models.MaycurPublicOfferingCompany, 0)
		for _, c := range codeCompany {
			saleNames := strings.Join(codeSales[c.Social], ",")
			ex := companyCodeVal[c.Social]
			if ex != nil {
				// 更新销售
				ex.SaleNames = saleNames
				ex.ModifyTime = time.Now().Local()
				if e = ex.Update(updateCols); e != nil {
					err = fmt.Errorf("更新客户信息失败, Err: %s", e.Error())
					return
				}
				continue
			}
			c.SaleNames = saleNames
			inserts = append(inserts, c)
			// 本次新增的客户也加入map, 因为可能出现下一页有上一页的客户, 下一次循环时更新
			companyCodeVal[c.Social] = c
		}
		ob := new(models.MaycurPublicOfferingCompany)
		if e = ob.CreateMulti(inserts); e != nil {
			err = fmt.Errorf("批量新增客户信息失败, Err: %s", e.Error())
			return
		}

		// 最后一页
		if data.Paginator.LastPage == currentPage {
			break
		}
		currentPage += 1
	}
	return
}

// GetPublicOfferingSaleLeader 获取公募销售对应的组长
func GetPublicOfferingSaleLeader() (leaderMap map[string][]string, err error) {
	saleOB := new(models.MaycurPublicOfferingSale)
	sales, e := saleOB.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
	if e != nil {
		err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error())
		return
	}
	if sales == nil {
		return
	}
	if len(sales) == 0 {
		return
	}

	// 销售组组长
	groupsLeader := make(map[string][]string)
	for _, s := range sales {
		// 存在这种数据->北京组、上海组
		gs := strings.Split(s.DeptText, "、")
		for _, g := range gs {
			if s.IsLeader == 1 {
				groupsLeader[g] = append(groupsLeader[g], s.Nickname)
			}
		}
	}

	// 销售对应组长
	leaderMap = make(map[string][]string)
	for _, s := range sales {
		// 组长置空
		ls := make([]string, 0)
		if s.IsLeader == 1 {
			leaderMap[s.Nickname] = ls
			continue
		}
		// 组员
		gs := strings.Split(s.DeptText, "、")
		for _, g := range gs {
			if len(groupsLeader[g]) > 0 {
				for _, l := range groupsLeader[g] {
					if !utils.InArrayByStr(ls, l) {
						ls = append(ls, l)
					}
				}
			}
		}
		leaderMap[s.Nickname] = ls
	}
	return
}
