package model

import (
	"app.yhyue.com/moapp/jybase/redis"
	"encoding/json"
	"fmt"
	IC "jyBXBuyer/rpc/init"
	"jyBXBuyer/rpc/type/bxbuyer"
	"log"
	"strconv"
	"strings"
	"sync"
	"time"

	MC "app.yhyue.com/moapp/jybase/common"
	"app.yhyue.com/moapp/jybase/encrypt"
	elastic "app.yhyue.com/moapp/jybase/es"
	"github.com/zeromicro/go-zero/core/logx"
)

const (
	HasContact = 1 // 采购单位是否有联系方式筛选项 1-有联系方式
	NoContact  = 2 //  无联系方式
)

type BScope struct {
	Keyword         []string `json:"keyword"`
	AdditionalWords []string `json:"additionalWords"`
	ExcludedWords   []string `json:"excludedWords"`
}
type supplyDataStruct struct {
	ProjectCount   int64
	BidCount       int64
	BidAmountCount float32
	ContactCount   int64
}

// 获取采购单位查询query
func BuyerListQuery(in *bxbuyer.BuyerListReq) (qstr string, CountQstr string) {
	query := `{%s "query":{"bool":{"must":[%s],"must_not": [{"term": {"buyer_name": ""}}],"should":[%s],"minimum_should_match": %d}} %s}`
	//21.1.20  为和画像保持一致  数据组要求 budget 改成 bidamount
	query_bool_should := `{"bool":{"should":[%s],"minimum_should_match": 1}}`
	sort := ""
	bools := []string{}
	musts := []string{}
	musts_should := []string{}
	//省份
	if len(in.Province) > 0 {
		musts_should = append(musts_should, fmt.Sprintf(`{"terms":{"province":["%s"]}}`, strings.Join(in.Province, "\",\"")))
	}
	//城市
	if len(in.City) > 0 {
		musts_should = append(musts_should, fmt.Sprintf(`{"terms":{"city":["%s"]}}`, strings.Join(in.City, "\",\"")))
	}
	if len(musts_should) > 0 {
		musts = append(musts, fmt.Sprintf(query_bool_should, strings.Join(musts_should, ",")))
	}
	//采购单位名称
	if in.BuyerName != "" {
		entNameQuery := fmt.Sprintf(`{"multi_match": {"query": "%s","type": "phrase", "fields": ["name"]}}`, in.BuyerName)
		musts = append(musts, entNameQuery)
	} else {
		sort = `,"sort":[{"updatetime":"desc"}]` // 仅无关键词时再

	}
	//采购单位类型
	buyerclass := in.BuyerClass
	if len(buyerclass) > 0 {
		Buyerclass := `{"terms":{"buyerclass":[`
		for k, v := range buyerclass {
			if k > 0 {
				Buyerclass += `,`
			}
			Buyerclass += `"` + v + `"`
		}
		Buyerclass += `]}}`
		musts = append(musts, Buyerclass)
	}
	// 采购单位联系方式  0-不限 1-有联系人 2-无联系人
	if in.IsContact != 0 {
		isContact := MC.If(in.IsContact == int64(HasContact), true, false)
		isContactStr := `{"term":{"is_contact":` + fmt.Sprint(isContact) + `}}`
		musts = append(musts, isContactStr)
	}
	boolsNum := 0
	qstr = fmt.Sprintf(query, fmt.Sprintf(`"from":%d,"size": %d,`, (in.PageNum-1)*in.PageSize, in.PageSize), strings.Join(musts, ","), strings.Join(bools, ","), boolsNum, sort)
	CountQstr = fmt.Sprintf(query, "", strings.Join(musts, ","), strings.Join(bools, ","), boolsNum, "")
	return
}

// 采购单位补充采购规模、项目数量、招标动态数量
func SupplyDataQuery(buyerList []string) (query string) {
	// 查近两年的数据   因为bigmember  BuyerMiniPortrait 查的默认是两年
	q := `{"size":0,"query": { "bool": { "must": [ {"terms": { "buyer": ["` + strings.Join(buyerList, "\",\"") + `"] }},{"range": {"jgtime": {"gte": %d,"lt": %d} }} ]}}, "aggs": { "buyerBuckets": {"terms": {"field": "buyer"
 },"aggs": {"bidAmountCount": {"sum": {"field": "bidamount"}}}}}}`
	start, end := getTimeRange()
	return fmt.Sprintf(q, start.Unix(), end.Unix())
}
func getTimeRange() (st, et time.Time) {
	now := time.Now()
	eYear := now.Year()
	sYear := now.Year() - 2
	//返回默认时间
	sTimeStamp := time.Date(sYear, 1, 1, 0, 0, 0, 0, time.Local)
	eTimeStamp := time.Date(eYear, now.Month(), now.Day(), now.Hour(), now.Minute(), 0, 0, time.Local)

	return sTimeStamp, eTimeStamp

}

const (
	P_INDEX                   = "projectset"
	P_TYPE                    = "projectset"
	P_redis_time              = 7 * 24 * 60 * 60 //redis存7天
	P_redis_key               = "buyerListCache" // 存缓存 100条数据
	BuyerIndex                = "buyer"          // 采购单位index
	BuyerType                 = "buyer"
	biddingIndex              = "bidding"
	biddingType               = "bidding"
	BuyerSupplyInfoRedisKey   = "BuyerSupplyInfo_%s"  // 采购单位补充信息缓存
	BuyerSupplyInfoRedisTime  = 2 * 60 * 60           // 采购单位补充信息缓存时间 一个小时
	BuyerProjectInfoRedisKey  = "BuyerProjectInfo_%s" // 采购单位补充项目信息缓存Key  (项目数量采购规模)
	BuyerProjectInfoRedisTime = 24 * 60 * 60          // 采购单位补充项目信息缓存时间
)

// GetBuyerList 查询采购单位列表
func GetBuyerList(qstr string, CountQuery string, isCache bool) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
	t1 := time.Now()
	total := elastic.Count(BuyerIndex, BuyerType, CountQuery) // 总数
	logx.Info("耗时1：", time.Since(t1))
	resp = &bxbuyer.BuyerListResp{
		Data: &bxbuyer.BuyerData{
			Count: total,
			List:  []*bxbuyer.BuyerList{},
		},
	}
	if total == 0 {
		return
	}
	start := time.Now()
	rs := elastic.Get(BuyerIndex, BuyerType, qstr) // 采购单位列表
	logx.Info("采购单位列表 es get查询耗时", time.Since(start))
	if rs == nil || len(*rs) == 0 {
		return
	}
	for i := 0; i < len(*rs); i++ {
		tmp := &bxbuyer.BuyerList{
			Buyer:      MC.ObjToString((*rs)[i]["name"]),
			Province:   MC.ObjToString((*rs)[i]["province"]),
			City:       MC.ObjToString((*rs)[i]["city"]),
			BuyerClass: MC.ObjToString((*rs)[i]["buyerclass"]),
		}
		buyerNames = append(buyerNames, tmp.Buyer)
		resp.Data.List = append(resp.Data.List, tmp)
	}
	logx.Info("耗时;", time.Since(t1).Seconds(), "秒--", time.Since(t1).Microseconds())
	return
}

// BuyerListRedisCache 空搜索 1.查询项目数量最多的前200个 2.然后 再查buyer里确认数据有效 100个 3.项目数量和采购规模单独存缓存 1天
//
//	func BuyerListRedisCache(query string, in *bxbuyer.BuyerListReq) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
//		//获取缓存数据
//		resp = &bxbuyer.BuyerListResp{
//			Data: &bxbuyer.BuyerData{
//				List: []*bxbuyer.BuyerList{},
//			},
//		}
//		t1 := time.Now()
//		logx.Info("耗时1：", time.Since(t1))
//		aggs := GetAggs(P_INDEX, P_TYPE, query)
//		logx.Info("查询语句：", query)
//		logx.Info("BuyerListRedisCache:", time.Since(t1))
//		type BuyerAggStruct struct {
//			Buckets []struct {
//				Key            string `json:"key,omitempty"`
//				Doc_count      int64  `json:"doc_count,omitempty"`
//				BidAmountCount struct {
//					Value float32 `json:"value,omitempty"`
//				} `json:"bidAmountCount"`
//			} `json:"buckets"`
//		}
//		var buyerBuckets = BuyerAggStruct{}
//		saveBuyerList := []*bxbuyer.BuyerList{} //100条数据 最后存起来
//		// 处理成map 用于后面格式化数据
//		if aggs == nil || aggs["buyerBuckets"] == nil {
//			return
//		}
//		bs, err := aggs["buyerBuckets"].MarshalJSON()
//		if err != nil {
//			resp.ErrCode = -1
//			resp.ErrMsg = "获取数据异常"
//			return
//		}
//		if len(bs) == 0 {
//			resp.ErrMsg = "暂无数据"
//			return
//		}
//		err = json.Unmarshal(bs, &buyerBuckets)
//		if err != nil || len(buyerBuckets.Buckets) == 0 {
//			resp.ErrMsg = "暂无数据"
//			return
//		}
//		for i := 0; i < len(buyerBuckets.Buckets); i++ {
//			if len(saveBuyerList) == int(IC.C.BuyerSearchLimit) {
//				break
//			}
//			// 查buyer  确认数据存在 补充 buyerclass 省份 城市信息
//			rs := GetBuyer(buyerBuckets.Buckets[i].Key)
//			if rs != nil && len(*rs) > 0 { // 存在 则追加
//				tmpBuyerInfo := (*rs)[0]
//				buyerInfo := &bxbuyer.BuyerList{
//					Buyer:      buyerBuckets.Buckets[i].Key,
//					Province:   MC.ObjToString(tmpBuyerInfo["province"]),
//					City:       MC.ObjToString(tmpBuyerInfo["city"]),
//					BuyerClass: MC.ObjToString(tmpBuyerInfo["buyerclass"]),
//				}
//				saveBuyerList = append(saveBuyerList, buyerInfo)
//				buyerNames = append(buyerNames, buyerInfo.Buyer)
//				// 项目数量和采购规模存缓存 1天
//				projectCacheData := supplyDataStruct{
//					ProjectCount:   buyerBuckets.Buckets[i].Doc_count,
//					BidAmountCount: buyerBuckets.Buckets[i].BidAmountCount.Value,
//				}
//				go func(buyer string, data supplyDataStruct) {
//					b, err := json.Marshal(data)
//					if err == nil {
//						redis.PutBytes("other", fmt.Sprintf(BuyerProjectInfoRedisKey, buyer), &b, BuyerProjectInfoRedisTime+GetRand(60))
//					}
//				}(buyerBuckets.Buckets[i].Key, projectCacheData)
//
//			}
//		}
//		if len(saveBuyerList) > 0 {
//			//  100 列表存redis 7天
//			go func(data []*bxbuyer.BuyerList) {
//				b, err := json.Marshal(data)
//				if err == nil {
//					redis.PutBytes("other", fmt.Sprintf(P_redis_key), &b, P_redis_time)
//				}
//			}(saveBuyerList)
//		} else {
//			return
//		}
//
//		// 根据页码返回数据
//		start := in.PageSize * (in.PageNum - 1)
//		end := in.PageSize * in.PageNum
//		resp.Data.Count = int64(len(saveBuyerList))
//		if end > int64(len(saveBuyerList)-1) {
//			end = int64(len(saveBuyerList) - 1)
//		}
//		resp.Data.List = saveBuyerList[start:end]
//		return
//	}
func BuyerListRedisCache(query string, in *bxbuyer.BuyerListReq) (buyerNames []string, resp *bxbuyer.BuyerListResp) {
	//获取缓存数据
	resp = &bxbuyer.BuyerListResp{
		Data: &bxbuyer.BuyerData{
			List: []*bxbuyer.BuyerList{},
		},
	}
	t1 := time.Now()
	rs := elastic.Get(BuyerIndex, BuyerType, query) // 采购单位列表
	logx.Info("空搜索采购单位列表 es get查询耗时", time.Since(t1))
	if rs == nil || len(*rs) == 0 {
		return
	}
	saveBuyerList := []*bxbuyer.BuyerList{} //最后缓存起来
	for i := 0; i < len(*rs); i++ {
		tmp := &bxbuyer.BuyerList{
			Buyer:      MC.ObjToString((*rs)[i]["name"]),
			Province:   MC.ObjToString((*rs)[i]["province"]),
			City:       MC.ObjToString((*rs)[i]["city"]),
			BuyerClass: MC.ObjToString((*rs)[i]["buyerclass"]),
		}
		buyerNames = append(buyerNames, tmp.Buyer)
		saveBuyerList = append(saveBuyerList, tmp)
	}
	if len(saveBuyerList) > 0 {
		//  100 列表存redis 7天
		go func(data []*bxbuyer.BuyerList) {
			b, err := json.Marshal(data)
			if err == nil {
				redis.PutBytes("other", fmt.Sprintf(P_redis_key), &b, P_redis_time)
			}
		}(saveBuyerList)
	} else {
		return
	}
	// 根据页码返回数据
	start := in.PageSize * (in.PageNum - 1)
	end := in.PageSize * in.PageNum
	resp.Data.Count = int64(len(saveBuyerList))
	if end > int64(len(saveBuyerList)) {
		end = int64(len(saveBuyerList))
	}
	resp.Data.List = saveBuyerList[start:end]
	logx.Info("空搜索整体耗时;", time.Since(t1).Seconds(), "秒--", time.Since(t1).Microseconds())
	return
}

// GetBuyer 查采购单位表 确认采购单位存在
func GetBuyer(buyerName string) *[]map[string]interface{} {
	q := `{"size":1,"_source":["buyerclass","province","city"],"query":{"bool":{"must":[{"term":{"buyer_name":"%s"}}]}}}`
	rs := elastic.Get(BuyerIndex, BuyerType, fmt.Sprintf(q, buyerName))
	return rs
}

// SupplyFollowInfo 补充是否关注信息
func SupplyFollowInfo(in *bxbuyer.BuyerListReq, buyerNames []string, resp *bxbuyer.BuyerListResp) *bxbuyer.BuyerListResp {

	//省份和城市 是否查询已关注信息 是否查询已领取信息
	//企业信用库qyxy_std 和es buyer库 查询省份和城市
	//客户领取
	t2 := time.Now()
	isRws := map[string]string{}
	if in.IsCheckReceive {
		isRws = IsReceived(buyerNames, in.EntUserId)
	}
	logx.Info("客户领取耗时：", time.Since(t2))
	//客户关注
	t3 := time.Now()
	isFws := map[string]bool{}
	if in.IsCheckFollow {
		isFws = IsFollowd(buyerNames, in.UserId)
	}
	logx.Info("采购单位关注耗时：", time.Since(t3))
	for _, bv := range resp.Data.List {
		if in.IsCheckReceive {
			if isRws[bv.Buyer] != "" {
				bv.IsReceived = true
				bv.RecId = isRws[bv.Buyer]
			}
		}
		if in.IsCheckFollow {
			if isFws[bv.Buyer] {
				bv.IsFollowed = true
			}
		}
	}
	return resp
}

// SupplyBuyerListData 补充字段   招标动态数量 项目数量 历史联系人数量 采购单位规模
func SupplyBuyerListData(buyerNames []string, resp *bxbuyer.BuyerListResp) *bxbuyer.BuyerListResp {
	//buyerNames 是否存在缓存 数据
	//如果没有 放到一个新的 []string
	needSearchBuyer := []string{}
	cacheMap := map[string]supplyDataStruct{}
	for i := 0; i < len(buyerNames); i++ {
		bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
		if err == nil && bs != nil && len(*bs) > 0 {
			tmp := supplyDataStruct{}
			if err := json.Unmarshal(*bs, &tmp); err == nil {
				cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据
			} else {
				needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
			}
		} else {
			needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查
		}

	}

	start := time.Now()
	t1 := time.Now()
	buyerMap := map[string]supplyDataStruct{} // 聚合的数据
	if len(needSearchBuyer) > 0 {
		query := SupplyDataQuery(needSearchBuyer) // 项目数量、采购规模
		// 聚合查
		aggs := GetAggs(P_INDEX, P_TYPE, query)
		logx.Info("查询语句：", query)
		logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
		type BuyerAggStruct struct {
			Buckets []struct {
				Key            string `json:"key,omitempty"`
				Doc_count      int64  `json:"doc_count,omitempty"`
				BidAmountCount struct {
					Value float32 `json:"value,omitempty"`
				} `json:"bidAmountCount"`
			} `json:"buckets"`
		}
		var buyerBuckets = BuyerAggStruct{}
		// 处理成map 用于后面格式化数据
		if aggs != nil && aggs["buyerBuckets"] != nil {
			bs, err := aggs["buyerBuckets"].MarshalJSON()
			if err != nil {
				resp.ErrCode = -1
				resp.ErrMsg = "获取数据异常"
			} else {
				if len(bs) == 0 {
					resp.ErrMsg = "暂无数据"
				} else {
					err := json.Unmarshal(bs, &buyerBuckets)
					logx.Info(err)
					if len(buyerBuckets.Buckets) > 0 {
						for _, v := range buyerBuckets.Buckets {
							buyerMap[v.Key] = supplyDataStruct{
								BidAmountCount: v.BidAmountCount.Value,
								ProjectCount:   v.Doc_count,
							}
						}
					}
				}
			}
		}
	}
	ch := make(chan int, 10)
	ch2 := make(chan int, 10)
	wg := &sync.WaitGroup{}
	for i := 0; i < len(resp.Data.List); i++ {
		buyer := resp.Data.List[i].Buyer
		// 先查缓存
		if cacheData, ok := cacheMap[buyer]; ok {
			resp.Data.List[i].BidAmountCount = cacheData.BidAmountCount
			resp.Data.List[i].ProjectCount = cacheData.ProjectCount
			resp.Data.List[i].BiddingCount = cacheData.BidCount
			resp.Data.List[i].ContactCount = cacheData.ContactCount
			continue
		}
		// 缓存里没有的再查数据补充
		if supplyData, ok := buyerMap[buyer]; ok {
			resp.Data.List[i].BidAmountCount = supplyData.BidAmountCount
			resp.Data.List[i].ProjectCount = supplyData.ProjectCount
		}
		ch2 <- 1
		wg.Add(1)
		go func(list *bxbuyer.BuyerList, buyer string) {
			defer func() {
				<-ch2
				wg.Done()
			}()
			list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
		}(resp.Data.List[i], buyer)
		ch <- 1
		wg.Add(1)
		go func(list *bxbuyer.BuyerList, buyer string) {
			defer func() {
				<-ch
				wg.Done()
			}()
			list.BiddingCount = GetNewBiddingCount(buyer)
		}(resp.Data.List[i], buyer)

	}
	wg.Wait()
	logx.Info("SupplyBuyerListData 整体耗时：", time.Since(start))

	//得到所有数据，包括 redis里的，再存一下
	go func(respList []*bxbuyer.BuyerList) {
		for i := 0; i < len(respList); i++ {
			tmp := supplyDataStruct{
				ContactCount:   respList[i].ContactCount,
				BidCount:       respList[i].BiddingCount,
				ProjectCount:   respList[i].ProjectCount,
				BidAmountCount: respList[i].BidAmountCount,
			}
			// 存redis
			b, err := json.Marshal(tmp)
			if err == nil {
				redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
			}
		}
	}(resp.Data.List)

	return resp
}

// 获取项目数量 采购单位规模
func getBuyerProjectCache(buyer string) (rs *supplyDataStruct) {
	bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerProjectInfoRedisKey, buyer))
	if err == nil && bs != nil && len(*bs) > 0 {
		if err := json.Unmarshal(*bs, &rs); err != nil {
			logx.Info("获取redis缓存，序列化异常")
		} else {
			return rs
		}
	}
	return
}

// BuyerSupplyInfo 补充字段
func BuyerSupplyInfo(buyerNames []string) (resp *bxbuyer.BuyerSupplyResp) {
	resp = &bxbuyer.BuyerSupplyResp{}
	start := time.Now()
	// buyerNames
	//buyerNames 是否存在缓存 数据
	//如果没有 放到一个新的 []string
	needSearchBuyer := []string{}
	cacheMap := map[string]supplyDataStruct{}
	buyerMap := map[string]supplyDataStruct{}
	for i := 0; i < len(buyerNames); i++ {
		bs, err := redis.GetBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, buyerNames[i]))
		if err == nil && bs != nil && len(*bs) > 0 {
			tmp := supplyDataStruct{}
			if err := json.Unmarshal(*bs, &tmp); err == nil {
				cacheMap[buyerNames[i]] = tmp // 拿到缓存的数据  采购规模 项目数量 联系人数量 招标动态数量
			} else {
				// 查缓存
				cacheProject := getBuyerProjectCache(buyerNames[i])
				if cacheProject != nil {
					buyerMap[buyerNames[i]] = *cacheProject
				} else {
					needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
				}

			}
		} else {
			// 查缓存
			cacheProject := getBuyerProjectCache(buyerNames[i])
			if cacheProject != nil {
				buyerMap[buyerNames[i]] = *cacheProject
			} else {
				needSearchBuyer = append(needSearchBuyer, buyerNames[i]) // 没有缓存的数据 后边再查采购规模和项目数量
			}
		}

	}
	if len(needSearchBuyer) > 0 {
		t1 := time.Now()
		query := SupplyDataQuery(buyerNames) // 项目数量、采购规模
		// 聚合查
		aggs := GetAggs(P_INDEX, P_TYPE, query)
		logx.Info("查询语句：", query)
		logx.Info("项目数量采购规模查询耗时:", time.Since(t1))
		type BuyerAggStruct struct {
			Buckets []struct {
				Key            string `json:"key,omitempty"`
				Doc_count      int64  `json:"doc_count,omitempty"`
				BidAmountCount struct {
					Value float32 `json:"value,omitempty"`
				} `json:"bidAmountCount"`
			} `json:"buckets"`
		}
		var buyerBuckets = BuyerAggStruct{}
		// 处理成map 用于后面格式化数据
		if aggs != nil && aggs["buyerBuckets"] != nil {
			bs, err := aggs["buyerBuckets"].MarshalJSON()
			if err != nil {
				resp.ErrCode = -1
				resp.ErrMsg = "获取数据异常"
			} else {
				if len(bs) == 0 {
					resp.ErrMsg = "暂无数据"
				} else {
					err := json.Unmarshal(bs, &buyerBuckets)
					logx.Info(err)
					if len(buyerBuckets.Buckets) > 0 {
						for _, v := range buyerBuckets.Buckets {
							buyerMap[v.Key] = supplyDataStruct{
								BidAmountCount: v.BidAmountCount.Value,
								ProjectCount:   v.Doc_count,
							}
						}
					}
				}
			}
		}
	}

	ch := make(chan int, 10)
	ch2 := make(chan int, 10)
	wg := &sync.WaitGroup{}
	for i := 0; i < len(buyerNames); i++ {
		buyer := buyerNames[i]
		resp.Data = append(resp.Data, &bxbuyer.SupplyData{
			Buyer: buyer,
		})
		// 先查缓存
		if cacheData, ok := cacheMap[buyer]; ok {
			resp.Data[i].BidAmountCount = cacheData.BidAmountCount
			resp.Data[i].ProjectCount = cacheData.ProjectCount
			resp.Data[i].BiddingCount = cacheData.BidCount
			resp.Data[i].ContactCount = cacheData.ContactCount
			continue
		}
		// 缓存里没有的再取查数据补充
		// 补充字段
		if supplyData, ok := buyerMap[buyer]; ok {
			resp.Data[i].BidAmountCount = supplyData.BidAmountCount
			resp.Data[i].ProjectCount = supplyData.ProjectCount
		}
		ch2 <- 1
		wg.Add(1)
		go func(list *bxbuyer.SupplyData, buyer string) {
			defer func() {
				<-ch2
				wg.Done()
			}()
			list.ContactCount = GetProjectContactCount(buyer) // 补充联系人字段
		}(resp.Data[i], buyer)
		ch <- 1
		wg.Add(1)
		go func(list *bxbuyer.SupplyData, buyer string) {
			defer func() {
				<-ch
				wg.Done()
			}()
			list.BiddingCount = GetNewBiddingCount(buyer)
		}(resp.Data[i], buyer)

	}
	wg.Wait()
	logx.Info(" 整体耗时：", time.Since(start))
	//得到所有数据，包括 redis里的，再存一下
	go func(respList []*bxbuyer.SupplyData) {
		for i := 0; i < len(respList); i++ {
			tmp := supplyDataStruct{
				ContactCount:   respList[i].ContactCount,
				BidCount:       respList[i].BiddingCount,
				ProjectCount:   respList[i].ProjectCount,
				BidAmountCount: respList[i].BidAmountCount,
			}
			// 存redis
			b, err := json.Marshal(tmp)
			if err == nil {
				redis.PutBytes("other", fmt.Sprintf(BuyerSupplyInfoRedisKey, respList[i].Buyer), &b, BuyerSupplyInfoRedisTime+GetRand(60))
			}
		}
	}(resp.Data)
	return
}

func GetProjectContactCount(buyerName string) int64 {
	start := time.Now()
	list := []string{}
	searchSql := fmt.Sprintf(`{"query":{"bool":{"filter":[{"term":{"buyer":"%s"}}]}},"_source":["list.buyerperson","list.buyertel"],"sort":[{"zbtime":"desc"}],"size":500}`, buyerName)
	projectList := elastic.Get(P_INDEX, P_TYPE, searchSql)
	logx.Info("GetProjectContactCount esget 耗时", time.Since(start), searchSql)
	if projectList == nil || len(*projectList) == 0 {
		return 0
	}
	//根据联系人和联系方式展示
	//多个项目同一个联系人；只展示最新项目
	//一个项目多个联系人；拆分展示
	repeatContacts := map[string]bool{}
	for _, rowData := range *projectList {
		mapList, ok := rowData["list"].([]interface{})
		if !ok || len(mapList) == 0 {
			continue
		}
		for i := len(mapList) - 1; i >= 0; i-- {
			thisMsg, ok := mapList[i].(map[string]interface{})
			if !ok || len(thisMsg) == 0 {
				continue
			}
			thisPhone, thisPerson := "", ""
			if thisPhone, _ = thisMsg["buyertel"].(string); thisPhone != "" {
				thisPerson, _ = thisMsg["buyerperson"].(string)
			}
			if thisPhone == "" { //联系人为空则不展示 dev4.7.3联系人为空展示此记录
				continue
			}
			//一个项目只选取一条公告联系人
			thisAddPerson := false
			//名字中多个联系人拆分
			for _, name := range strings.Split(thisPerson, ",") {
				thisName := strings.TrimSpace(name)
				if thisName == "" && thisAddPerson { //联系人为空则不展示
					continue
				}
				thisAddPerson = true
				repeatKey := fmt.Sprintf("%s_%s", thisName, thisPhone)
				if repeatContacts[repeatKey] {
					continue
				}
				repeatContacts[repeatKey] = true
				list = append(list, thisPhone)
			}
			if thisAddPerson {
				break
			}
		}
	}
	logx.Info("GetProjectContactCount 单次耗时：", time.Since(start))
	return int64(len(list))
}
func GetNewBiddingCount(buyer string) int64 {
	start := time.Now()
	if buyer == "" {
		return 0
	}
	var mustQuery []string
	st, et := getTimeRange()
	mustQuery = append(mustQuery, fmt.Sprintf(`{"range":{"publishtime":{"gte":%d,"lte":%d}}}`, st.Unix(), et.Unix()))
	mustQuery = append(mustQuery, fmt.Sprintf(`{"term": {"buyer": "%s"}}`, buyer))
	aa := fmt.Sprintf(`{"query":{"bool":{"must":[%s]}}}`, strings.Join(mustQuery, ","))
	count := elastic.Count(biddingIndex, biddingType, aa)
	logx.Info("GetNewBiddingCount 单次耗时：", buyer, time.Since(start))
	return count
}

// 聚合查询
func GetAggs(index, itype, query string) (aggs map[string]json.RawMessage) {
	aggs, _, _ = elastic.GetAggs(index, itype, query)
	return
}

type buyerInfo struct {
	Province string
	City     string
}

// 潜在客户 获取省份和城市
func GetBuyerInfo(buyerNames []string) (infoMap map[string]buyerInfo) {
	var buyerInfoQuery = `{"query": {"bool": {"must": [{"terms": {"%s": [%s]}}],"must_not": [],"should": []}},"from": 0,"size": 50,"sort": []}`
	query := fmt.Sprintf(buyerInfoQuery, "buyer_name", `"`+strings.Join(buyerNames, `","`)+`"`)
	list := *elastic.Get("buyer", "buyer", query)
	if list != nil {
		if len(list) > 0 {
			infoMap = map[string]buyerInfo{}
			for _, v := range list {
				infoMap[v["name"].(string)] = buyerInfo{
					Province: MC.If(v["province"] != nil, MC.ObjToString(v["province"]), "").(string),
					City:     MC.If(v["city"] != nil, MC.ObjToString(v["city"]), "").(string),
				}
			}
		}
	} else {
		logx.Info("采购单位获取地区信息异常")
	}
	return
}

var fc = "follow_customer" //关注客户表
// 采购单位是否作为客户已被关注
func IsFollowd(buyerNames []string, userId string) (isFws map[string]bool) {
	queryMap := map[string]interface{}{
		"userId": userId,
		"name": map[string]interface{}{
			"$in": buyerNames,
		},
	}
	list, ok := IC.Mgo.Find(fc, queryMap, `{"_id":1}`, nil, false, -1, -1)
	if ok && len(*list) > 0 {
		isFws = map[string]bool{}
		for _, lv := range *list {
			if MC.ObjToString(lv["name"]) != "" {
				isFws[MC.ObjToString(lv["name"])] = true
			}
		}
	} else {
		logx.Info("采购单位是否已关注信息异常  or  未查到数据")
	}
	return
}

var (
	Entniche_customer      = "entniche_customer"
	Entniche_user_customer = "entniche_user_customer"
)

// 领取状态
func IsReceived(buyerNames []string, entUserId string) (isRws map[string]string) {
	//新加领取的客户id----保证领取的唯一性
	aa := fmt.Sprintf("SELECT ecn.id,  ecn.name  FROM %s ecn,%s  euu WHERE ecn.id = euu.customer_id AND euu.user_id =? AND ecn.`name` IN  ('%s') AND (euu.source_type =1 or euu.source_type=4)", Entniche_customer, Entniche_user_customer, strings.Join(buyerNames, "','"))
	log.Println(aa)
	receInfos := IC.MainMysql.SelectBySql(fmt.Sprintf("SELECT ecn.id,  ecn.name  FROM %s ecn,%s  euu WHERE ecn.id = euu.customer_id AND euu.user_id =? AND ecn.`name` IN  ('%s') AND (euu.source_type =1 or euu.source_type=4)", Entniche_customer, Entniche_user_customer, strings.Join(buyerNames, "','")), entUserId)
	if receInfos != nil {
		if len(*receInfos) > 0 {
			isRws = map[string]string{}
			for _, rv := range *receInfos {
				if MC.ObjToString(rv["name"]) != "" && strconv.Itoa(MC.IntAll(rv["id"])) != "" {
					isRws[MC.ObjToString(rv["name"])] = encrypt.SE.Encode2HexByCheck(strconv.Itoa(MC.IntAll(rv["id"])))
				}
			}
		}
	} else {
		logx.Info("采购单位是否已领取信息异常")
	}
	return
}

// 是否为空请求
func CheckEmpty(in *bxbuyer.BuyerListReq) bool {
	if in.BuyerName == "" && len(in.BuyerClass) == 0 && len(in.Province) == 0 && len(in.City) == 0 && in.IsContact == 0 {
		return true
	}
	return false
}

//缓存数据查询

// 获取采购单位查询query
func BuyerListRedisCacheQuery() (qstr string) {
	qstr = `{"size":%d,"query":{"bool":{"must":[],"must_not":[{"term":{"buyer_name":""}}]}},"sort":[{"updatetime":"desc"}]}`
	return fmt.Sprintf(qstr, IC.C.BuyerSearchLimit)
}
