package main

import (
	utils "app.yhyue.com/data_processing/common_utils"
	"context"
	"fmt"
	"github.com/robfig/cron/v3"
	"go.uber.org/zap"
	"jygit.jydev.jianyu360.cn/data_processing/common_utils/log"
	"jygit.jydev.jianyu360.cn/data_processing/common_utils/mongodb"
	"jygit.jydev.jianyu360.cn/data_processing/common_utils/mysqldb"
	"sync"
	"time"
)

var (
	Mgo       *mongodb.MongodbSim
	MgoP      *mongodb.MongodbSim
	MgoSpider *mongodb.MongodbSim
	Mysql     *mysqldb.Mysql
	//EsClient    *es.Client
	SpiderSites = make([]string, 0) //排除，竞品站点
)

func main() {
	local, _ := time.LoadLocation("Asia/Shanghai")
	c := cron.New(cron.WithLocation(local), cron.WithSeconds())
	eid, err := c.AddFunc(GF.Cron.Spec, specData)
	if err != nil {
		log.Info("main", zap.Any("AddFunc err", err))
	}
	log.Info("main", zap.Any("eid", eid))

	c.Start()
	defer c.Stop()

	select {}

}

func specData() {
	dealBidding()
	time.Sleep(time.Minute * 10)
	dealProject()
	go deleteData()
	log.Info("main", zap.String("结束", "over"))
}

//deleteData 删除数据
func deleteData() {
	defer utils.Catch()
	now := time.Now()
	if GF.Cron.Delete >= 0 {
		log.Error("deleteData", zap.String("配置文件错误", "没有配置定时删除的delete"))
		return
	}
	deleteTime := time.Date(now.Year(), now.Month(), now.Day()+GF.Cron.Delete, 0, 0, 0, 0, now.Location())
	deleteStr := deleteTime.Format("2006-01-02 15:04:05")
	rowsPerPage := 10000

	finalId := 0
	lastSql := fmt.Sprintf(`
	 SELECT
             t.id

         FROM
             ods_datamonitoring_bidding AS t

         WHERE   t.comeintime < "%s"

         ORDER BY t.id DESC  LIMIT 1
`, deleteStr)

	lastInfo := Mysql.SelectBySql(lastSql)
	if len(*lastInfo) > 0 {
		finalId = utils.IntAll((*lastInfo)[0]["id"])
	}

	log.Info("deleteData", zap.Int("finalId", finalId))
	lastid, total := 0, 0

	for {
		query := fmt.Sprintf(`
SELECT
              t.id
          FROM
              ods_datamonitoring_bidding AS t

         WHERE t.id > %d  && t.comeintime < "%s"
         ORDER BY t.id ASC

         LIMIT %d;
     `, lastid, deleteStr, rowsPerPage)

		ctx := context.Background()
		rows, err := Mysql.DB.QueryContext(ctx, query)
		if err != nil {
			log.Info("deleteData", zap.Any("QueryContext err", err))
		}

		if finalId == lastid {
			log.Info("deleteData over", zap.Any("total", total), zap.Any("lastid", lastid))
			break
		}

		columns, err := rows.Columns()
		if err != nil {
			log.Info("deleteData", zap.Any("rows.Columns", err))
		}

		for rows.Next() {
			scanArgs := make([]interface{}, len(columns))
			values := make([]interface{}, len(columns))
			ret := make(map[string]interface{})

			for k := range values {
				scanArgs[k] = &values[k]
			}

			err = rows.Scan(scanArgs...)
			if err != nil {
				log.Info("deleteData", zap.Any("rows.Scan", err))
				break
			}

			for i, col := range values {
				if v, ok := col.([]uint8); ok {
					ret[columns[i]] = string(v)
				} else {
					ret[columns[i]] = col
				}
			}

			total++
			if total%1000 == 0 {
				log.Info("deleteData", zap.Int("current total", total))
			}
			lastid = utils.IntAll(ret["id"])

			where := map[string]interface{}{
				"id": ret["id"],
			}
			Mysql.Delete("ods_datamonitoring_bidding", where)

			ret = make(map[string]interface{})
		}

		rows.Close()

		if err := rows.Err(); err != nil {
			log.Info("deleteData", zap.Any("err", err))
		}

	}

	log.Info("deleteData", zap.Int("结束，total：", total))

}

func dealBidding() {
	sess := Mgo.GetMgoConn()
	defer Mgo.DestoryMongoConn(sess)
	// 指定对应的时间格式
	//layout := "2006-01-02 15:04:05"
	// 获取当前时间
	now := time.Now()

	//targetTime := time.Date(now.Year(), now.Month(), now.Day()+GF.Cron.Start, 04, 20, 0, 0, now.Location())
	targetTime := time.Date(now.Year(), now.Month(), now.Day()+GF.Cron.Start, 0, 0, 0, 0, now.Location())
	todayTime := time.Date(now.Year(), now.Month(), now.Day()+GF.Cron.End, 0, 0, 0, 0, now.Location())

	q := map[string]interface{}{
		"comeintime": map[string]interface{}{
			"$gt":  targetTime.Unix(),
			"$lte": todayTime.Unix(),
		},
	}
	log.Info("dealBidding", zap.Any("q", q))
	query := sess.DB(GF.Mongob.DB).C(GF.Mongob.Coll).Find(q).Select(map[string]interface{}{
		"contenthtml": 0}).Iter()
	count := 0

	ch := make(chan bool, 10)
	wg := &sync.WaitGroup{}

	for tmp := make(map[string]interface{}); query.Next(tmp); count++ {
		if count%1000 == 0 {
			log.Info("dealBidding", zap.Int("current", count))
		}

		ch <- true
		wg.Add(1)
		go func(tmp map[string]interface{}) {
			defer func() {
				<-ch
				wg.Done()
			}()

			saveBidding(tmp)
		}(tmp)
		tmp = map[string]interface{}{}
	}

	wg.Wait()
	log.Info("dealBidding", zap.Int("over ", count))
	//没有数据时，发送邮件
	if count == 0 {
		SendMail("每日数据监控", "查询数据为空，请处理")
	}
}

//saveBidding 保存bidding数据
func saveBidding(tmp map[string]interface{}) {
	sess := MgoP.GetMgoConn()
	defer MgoP.DestoryMongoConn(sess)

	//针对产权数据，暂时不入es 索引库
	if utils.IntAll(tmp["infoformat"]) == 3 {
		return
	}
	if sensitive := utils.ObjToString(tmp["sensitive"]); sensitive == "测试" { //bidding中有敏感词，不生索引
		tmp = make(map[string]interface{})
		return
	}

	insert := make(map[string]interface{})
	id := mongodb.BsonIdToSId(tmp["_id"])
	insert["bidding_id"] = id
	insert["spidercode"] = tmp["spidercode"]
	insert["site"] = tmp["site"]
	site := tmp["site"].(string)
	//竞品网站数据，直接过滤
	if IsInStringArray(site, SpiderSites) {
		return
	}

	if tmp["comeintime"] != nil {
		ctime, _ := convertToTime(tmp["comeintime"])
		insert["comeintime"] = ctime.Format("2006-01-02 15:04:05")
	}

	if tmp["publishtime"] != nil {
		putime, _ := convertToTime(tmp["publishtime"])
		insert["publishtime"] = putime.Format("2006-01-02 15:04:05")
	}

	if tmp["pici"] != nil {
		ptime, _ := convertToTime(tmp["pici"])
		insert["es_bidding_pici"] = ptime.Format("2006-01-02 15:04:05")
	} else {
		ctime, _ := convertToTime(tmp["comeintime"])
		insert["es_bidding_pici"] = ctime.Add(time.Minute * 10).Format("2006-01-02 15:04:05")
	}

	if utils.IntAll(tmp["extracttype"]) == -1 || utils.IntAll(tmp["dataprocess"]) == 7 {
		//insert["is_repeat"] = 1
		return
	} else {
		insert["is_repeat"] = 0
	}

	if tmp["area"] != nil {
		area := utils.ObjToString(tmp["area"])
		where := map[string]interface{}{
			"area":     area,
			"city":     "",
			"district": "",
		}
		res := Mysql.FindOne("code_area", where, "", "code asc")
		if res != nil {
			data := *res
			if len(data) > 0 {
				insert["crea_code"] = data["code"]
			}
		}
	} else {
		insert["crea_code"] = ""
	}

	if tmp["city"] != nil {
		area := utils.ObjToString(tmp["area"])
		city := utils.ObjToString(tmp["city"])
		where := map[string]interface{}{
			"area":     area,
			"city":     city,
			"district": "",
		}
		res := Mysql.FindOne("code_area", where, "", "code asc")
		if res != nil {
			data := *res
			if len(data) > 0 {
				insert["city_code"] = data["code"]
			}
		}
	} else {
		insert["city_code"] = ""
	}

	if tmp["district"] != nil {
		area := utils.ObjToString(tmp["area"])
		city := utils.ObjToString(tmp["city"])
		district := utils.ObjToString(tmp["district"])
		where := map[string]interface{}{
			"area":     area,
			"city":     city,
			"district": district,
		}
		res := Mysql.FindOne("code_area", where, "", "code asc")
		if res != nil {
			data := *res
			if len(data) > 0 {
				insert["district_code"] = data["code"]
			}
		}
	} else {
		insert["district_code"] = ""
	}

	insert["project_id"] = ""
	insert["updatetime"] = time.Now().Format("2006-01-02 15:04:05")

	//查询MongoDB project 信息
	wherep := map[string]interface{}{
		"ids": id,
	}
	count := 0
	query := sess.DB(GF.Mongop.DB).C(GF.Mongop.Coll).Find(wherep).Limit(1).Iter()
	for p := make(map[string]interface{}); query.Next(p); count++ {
		projectId := mongodb.BsonIdToSId(p["_id"])
		insert["project_id"] = projectId
		if p["pici"] != nil {
			time, _ := convertToTime(p["pici"])
			insert["project_pici"] = time.Format("2006-01-02 15:04:05")
			insert["es_project_pici"] = time.Format("2006-01-02 15:04:05")
		}
	}

	if len(insert) > 0 {
		insertId := Mysql.Insert(GF.Mysql.Table, insert)
		if insertId <= 0 {
			log.Info("saveBidding", zap.Any("insertId", insertId), zap.Any("insert", insert))
		}
	}

}

//dealProject 更新项目信息
func dealProject() {
	buyerPool := make(chan bool, 5) //控制线程数
	wg := &sync.WaitGroup{}

	sql := fmt.Sprintf(`select * from %s where project_id = '' and is_repeat = 0 `, GF.Mysql.Table)

	rows, err := Mysql.DB.Query(sql)
	if err != nil {
		log.Info("dealProject", zap.Any("QueryContext err", err))
	}

	columns, err := rows.Columns()
	if err != nil {
		log.Info("dealProject", zap.Any("rows.Columns", err))
	}
	total := 0
	for rows.Next() {
		total++
		scanArgs := make([]interface{}, len(columns))
		values := make([]interface{}, len(columns))
		ret := make(map[string]interface{})

		for k := range values {
			scanArgs[k] = &values[k]
		}

		err = rows.Scan(scanArgs...)
		if err != nil {
			log.Info("dealProject", zap.Any("rows.Scan", err))
			break
		}

		for i, col := range values {
			if v, ok := col.([]uint8); ok {
				ret[columns[i]] = string(v)
			} else {
				ret[columns[i]] = col
			}
		}

		//
		buyerPool <- true
		wg.Add(1)

		if total%100 == 0 {
			log.Info("dealProject", zap.Int("current", total), zap.Any("bidding_id", ret["bidding_id"]))
		}

		go func(tmp map[string]interface{}) {
			defer func() {
				<-buyerPool
				wg.Done()
			}()
			updateProject(tmp)

		}(ret)

		ret = make(map[string]interface{})
	}

	rows.Close()
	wg.Wait()

	log.Info("dealProject", zap.String("deal", "over"))
}

func updateProject(tmp map[string]interface{}) {
	sess := MgoP.GetMgoConn()
	defer MgoP.DestoryMongoConn(sess)

	update := map[string]interface{}{}
	id := mongodb.BsonIdToSId(tmp["bidding_id"])
	//更新MySQL where
	where := map[string]interface{}{
		"id": tmp["id"],
	}

	timenow := time.Now().Format("2006-01-02 15:04:05")
	//查询MongoDB project 信息
	wherep := map[string]interface{}{
		"ids": id,
	}
	count := 0
	query := sess.DB(GF.Mongop.DB).C(GF.Mongop.Coll).Find(wherep).Limit(1).Iter()
	for p := make(map[string]interface{}); query.Next(p); count++ {
		projectId := mongodb.BsonIdToSId(p["_id"])
		update["project_id"] = projectId
		if p["pici"] != nil {
			time, _ := convertToTime(p["pici"])
			update["project_pici"] = time.Format("2006-01-02 15:04:05")
			update["es_project_pici"] = time.Format("2006-01-02 15:04:05")
			update["updatetime"] = timenow
		}
	}

	if len(update) > 0 {
		res := Mysql.Update(GF.Mysql.Table, where, update)
		if !res {
			log.Info("updateProject", zap.Any("update", update), zap.Any("where", where))
		}
	}

}
