package cron

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"time"

	"github.com/dghubble/oauth1"
	"github.com/parnurzeal/gorequest"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"courseSign/server/global"
	"courseSign/server/model/twi"
	"courseSign/server/service"
	"courseSign/server/utils"
	"courseSign/server/utils/TwiApi"
)

type TwiJob struct {
	JobName string
	Config *oauth1.Config
	Client *gorequest.SuperAgent
}

var isTwiJobRun bool
var jwtService              = service.ServiceGroupApp.SystemServiceGroup.JwtService

// Run
// 检查子任务是否完成
func (job TwiJob) Run() {
	job.JobName = "TwiJob"
	if isTwiJobRun {
		global.GVA_LOG.Info(job.JobName, zap.String("job", "already run"))
		return
	}
	isTwiJobRun = true
	global.GVA_LOG.Info(job.JobName, zap.String("job", "start"))
	t := time.Now()
	defer func() {
		isTwiJobRun = false
		global.GVA_LOG.Info(job.JobName, zap.String("cost", time.Since(t).String()))
	}()
	job.Client = gorequest.New()
	var err error
	if global.GVA_CONFIG.Twitter.ApiKey == "" || global.GVA_CONFIG.Twitter.ApiSecret == "" {
		global.GVA_LOG.Error("twitter key 未设置")
		return
	}
	job.Config = TwiApi.GetOauthConfig(global.GVA_CONFIG.Twitter.ApiKey,global.GVA_CONFIG.Twitter.ApiSecret)
	// 同步已授权登录 获取到accessToken and accessSecret twitter用户信息到数据库
	// err = job.SyncTwiUserInfo()
	// if err != nil {
	// 	global.GVA_LOG.Error(job.JobName, zap.String("SyncTwiUserInfo err", err.Error()))
	// 	return
	// }
	// 定时查询同步bityuan的关注者
	// err = job.SyncBityuanFollows()
	// if err != nil {
	// 	global.GVA_LOG.Error(job.JobName, zap.String("SyncBityuanFollows err", err.Error()))
	// 	return
	// }
	err = job.QueryAction()
	if err != nil {
		global.GVA_LOG.Error(job.JobName,zap.String("query action err",err.Error()))
		return
	}
	global.GVA_LOG.Info(job.JobName, zap.String("job", "done"))
	return
}
// QueryFinishUsersAndSendRewards
// 查询更新活动结束截止后+1h（防止截止前几分钟用户完成任务没有计入奖励） 有多少用户完成整个活动 然后分配奖励
func (job *TwiJob) QueryFinishUsersAndSendRewards() error {
	actions := make([]*twi.TwiActList,0)
	nt := time.Now()
	err := global.GVA_DB.Model(&twi.TwiActList{}).Where("end_time < ?",nt).Find(&actions).Error
	if err != nil {
		global.GVA_LOG.Error("QueryFinishUsersAndSendRewards",zap.Error(err))
		return err
	}
	for _, v := range actions {
		// 剩余人数为0
		if *v.RewardPersonRemain == 0{
			global.GVA_LOG.Info(job.JobName,zap.Any("活动编号 已人数分配完毕",v.ID))
			continue
		}

		// 剩余金额为0
		if *v.RewardAmountRemain == 0 {
			global.GVA_LOG.Info(job.JobName,zap.Any("活动编号 已金额分配完毕",v.ID))
			continue
		}

		switch *v.Type {
			// 先到先得
		case twi.ActionRewardSendTypeNormal:
			err = job.ActionSendRewardNormal(v)
			if err != nil {
				return err
			}
			// 随机分配
		case twi.ActionRewardSendTypeRand:
			err = job.ActionSendRewardRand(v)
			if err != nil {
				return err
			}
		}

	}
	return nil
}

func (job *TwiJob) ActionSendRewardRand(v *twi.TwiActList) error {
	var err error
	// 预留一小时 确认每个完成的任务的记录同步至sql
	if v.EndTime.Unix() + 3600 > time.Now().Unix() {
		global.GVA_LOG.Info("未满一小时",zap.Any("活动编号",v.ID))
		return nil
	}
	// 查询子任务数量

	actTemp := make([]*twi.TwiActTemplate,0)
	err = global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("act_id = ?",v.ID).Find(&actTemp).Error
	if err != nil {
		global.GVA_LOG.Error("query act temp err",zap.Error(err))
		return err
	}

	// 查询子任务用户完成数量 = 则表示全部子任务完成 = 活动完成可以分配奖励
	type countSum struct {
		Uid int64 `json:"uid"`
		Count int64 `json:"count"`
	}

	userData := make([]*countSum,0)
	err = global.GVA_DB.Model(&twi.TwiActFinishDetail{}).Select("count(*) as count").Where("act_id = ? and finish_status = ?",v.ID,true).Group("uid").Scan(&userData).Error
	if err != nil {
		global.GVA_LOG.Error("query act temp err",zap.Error(err))
		return err
	}
	doneUsers := make([]*countSum,0)
	randomUsers := make([]*countSum,10)
	for _, vv := range userData {
		// 活动任务子任务都完成
		if int(vv.Count) == len(actTemp) {
			doneUsers = append(doneUsers,vv)
		}
	}
	global.GVA_LOG.Info(job.JobName,zap.Any("done users",doneUsers))
	// r := rand.NewSource(time.Now().UnixNano())
	rand.Seed(time.Now().UnixNano())
	perm := rand.Perm(len(doneUsers))
	for i:= 0; i < 10 ;i++ {
		randomUsers[i] = doneUsers[perm[i]]
	}
	for _, vv := range randomUsers {
		err = job.SendRewards(vv.Uid,v)
		if err != nil {
			global.GVA_LOG.Error(job.JobName,zap.String("send rewards err",err.Error()))
			return err
		}
	}
	return nil
}

func (job *TwiJob) ActionSendRewardNormal(v *twi.TwiActList) error {
	// 查询子任务数量

	actTemp := make([]*twi.TwiActTemplate,0)
	err := global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("act_id = ?",v.ID).Find(&actTemp).Error
	if err != nil {
		global.GVA_LOG.Error("query act temp err",zap.Error(err))
		return err
	}

	// 查询子任务用户完成数量 = 则表示全部子任务完成 = 活动完成可以分配奖励
	type countSum struct {
		Uid int64 `json:"uid"`
		Count int64 `json:"count"`
	}

	userData := make([]*countSum,0)
	err = global.GVA_DB.Model(&twi.TwiActFinishDetail{}).Select("count(*) as count").Where("act_id = ? and finish_status = ?",v.ID,true).Group("uid").Scan(&userData).Error
	if err != nil {
		global.GVA_LOG.Error("query act temp err",zap.Error(err))
		return err
	}

	for _, vv := range userData {
		// 活动任务子任务都完成
		if int(vv.Count) == len(actTemp) {
			err = job.SendRewards(vv.Uid,v)
			if err != nil {
				global.GVA_LOG.Error("SendRewards err",zap.Error(err))
				return err
			}
		}
	}
	return nil
}

// SendRewards
// 发送奖励
// 先确定分配方式 => 确定币种 => 确定金额 => 发送交易 => 同步数据至 finish 表
func (job *TwiJob) SendRewards(uid int64,act *twi.TwiActList) error {

	tx := global.GVA_DB.Begin()
	finishRecord := twi.TwiActFinish{
		UserId:       nil,
		TwiActId:     nil,
		RewardType:   nil,
		Amount:       nil,
		Hash:         "",
		RewardStatus: nil,
	}
	amount := utils.Decimal(*act.RewardAmount / float64(*act.RewardPerson),2) // 保留2位
	*finishRecord.UserId = int(uid)
	*finishRecord.RewardStatus = twi.ActionFinishStatusNormal
	*finishRecord.RewardType = *act.RewardType
	*finishRecord.TwiActId = int(act.ID)
	*finishRecord.Amount = amount
	err := tx.Save(finishRecord).Error
	if err != nil {
		tx.Rollback()
		global.GVA_LOG.Error(job.JobName,zap.Any("create finish record err",err))
		return err
	}
	err = tx.Model(&twi.TwiActList{}).Where("id = ?",act.ID).
		Updates(
			map[string]interface{}{
				"reward_amount_remain":gorm.Expr("reward_amount_remain - ?",amount),
				"reward_person_remain":gorm.Expr("reward_person_remain - ?",1),
			}).Error
	if err != nil {
		tx.Rollback()
		global.GVA_LOG.Error(job.JobName,zap.Any("update act list err",err))
		return err
	}

	return nil
}

// SyncBityuanFollows 查询 bityuan 关注者
func (job *TwiJob) SyncBityuanFollows() error {
	return nil
}

// QueryAction
// 遍历任务表 查询对应的任务
// 关注 转发 喜欢 跳转 引用 评论 具体操作完成写入 twi_act_finish_detail
// 一个任务所有操作都完成了再写入twi_act_finish
func (job TwiJob) QueryAction() error {
	actionList := make([]twi.TwiActList,0)
	err := global.GVA_DB.Model(&twi.TwiActList{}).Where("status = ?",twi.ActionStatusOnline).Find(&actionList).Error
	if err != nil {
		return err
	}
	global.GVA_LOG.Info("上线活动数量:",zap.Int("num",len(actionList)))
	for _, v := range actionList {
		// 查询活动下面的具体任务
		templateList := make([]twi.TwiActTemplate,0)
		err = global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("act_id = ?",v.ID).Find(&templateList).Error
		if err != nil {
			return err
		}
		if len(templateList) == 0 {
			global.GVA_LOG.Error("活动不存在任务",zap.Any("编号",v.ID))
			continue
		}

		// 查询具体任务完成情况
		for _, vv := range templateList {
			err = job.QueryActionTemplate(vv)
			if err != nil {
				global.GVA_LOG.Error("QueryActionTemplate ",zap.Error(err))
				return err
			}
		}
	}
	return nil
}

// 查询具体任务
func (job TwiJob) QueryActionTemplate(template twi.TwiActTemplate) error {
	// 推特平台
	if *template.ActPlatform == twi.ActionTemplateTwitter {
		switch *template.ActType {
		case twi.ActionTypeFollow:		// 关注
			global.GVA_LOG.Info("ActionTypeFollow")
			return nil
		case twi.ActionTypeLike:		// 喜欢
			return job.QueryActionTypeLike(template)
		case twi.ActionTypeRetweeted:   // 转发
			return job.QueryActionRetweeted(template)
		case twi.ActionTypeHref:        // 跳转
		case twi.ActionTypeQuote:       // 引用
			// return job.QueryActionQuoteTweets(template)
		case twi.ActionTypeReply:       // 回复
		}
	} else if *template.ActType == twi.ActionTemplateTelegram { // 电报

	} else {
		return errors.New("unknown action platform")
	}
	return nil
}

// QueryActionQuoteTweets
// 转贴查询
// id,max_results,pagination_token,exclude,expansions,tweet.fields,media.fields,poll.fields,place.fields,user.fields
// func (job TwiJob) QueryActionQuoteTweets(template twi.TwiActTemplate) error {
// 	id := template.ActKey
// 	// twitterId := global.GVA_CONFIG.Twitter.TwitterId
// 	token := oauth1.NewToken(global.GVA_CONFIG.Twitter.AccessToken,global.GVA_CONFIG.Twitter.AccessSecret)
//
// 	httpClient := job.Config.Client(oauth1.NoContext, token)
// 	// client := twitter.NewClient(httpClient)
//
// 	// 查询帖子信息
// 	path := TwiApi.QuoteTweetLookupEndpoint.UrlID(TwiApi.TwiApiUrl,id)
// 	resp, _ := httpClient.Get(path)
// 	defer resp.Body.Close()
// 	body, _ := ioutil.ReadAll(resp.Body)
// 	fmt.Printf("QueryActionTypeLike Raw Response Body:\n%v\n", string(body))
// 	respBody := struct {
// 		*twi.TweetRaw
// 		Meta *twi.QuoteTweetsLookupMeta `json:"meta"`
// 	}{}
// 	TwiApi.GetLimitRate(resp.Header,resp.Request.URL.String())
// 	err := json.Unmarshal(body,&respBody)
// 	if err != nil {
// 		return err
// 	}
//
// 	// TODO 是否请求下一页
// 	if respBody.Meta.NextToken != "" {
//
// 	}
//
// 	if len(respBody.Users) > 0 {
// 		finishTime := time.Now()
// 		finishUsers := make([]*twi.UserActionInfo,0)
// 		err = global.GVA_DB.Raw("select ta.id as tempFinishId," +
// 			"ta.act_id as actId,ta.template_id as templateId," +
// 			"tm.address,tm.id,tm.twi_username as twiUsername," +
// 			"tm.tele_username as teleUsername " +
// 			"ta.finish_status as tempFinishStatus " +
// 			"from twi_act_finish_detail as ta LEFT JOIN twi_metamask as tm " +
// 			"on ta.uid = tm.id ").Scan(&finishUsers).Error
// 		if err != nil {
// 			return err
// 		}
// 		if len(finishUsers) == 0 {
// 			return nil
// 		}
// 		for _,v := range finishUsers {
// 			var isDone bool
// 			for _, vv := range respBody.Users {
// 				if v.TwiUsername == vv.UserName {
// 					isDone = true
// 					break
// 				}
// 			}
// 			// 子任务完成 标记状态
// 			if isDone && !v.TempFinishStatus{
// 				err = global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("id = ?",v.TempFinishId).Updates(map[string]interface{}{"finish_time":finishTime,"finish_status":true}).Error
// 				if err != nil {
// 					global.GVA_LOG.Error("update status ERR",zap.Error(err))
// 					return err
// 				}
// 				global.GVA_LOG.Info("转发任务完成",zap.String("username",v.TwiUsername))
// 			}
// 		}
// 	}
// 	return nil
// }

// QueryActionRetweeted
// 转贴查询
// id,max_results,pagination_token,expansions,tweet.fields,user.fields
func (job TwiJob) QueryActionRetweeted(template twi.TwiActTemplate) error {
	id := template.ActKey
	// twitterId := global.GVA_CONFIG.Twitter.TwitterId
	token := oauth1.NewToken(global.GVA_CONFIG.Twitter.AccessToken,global.GVA_CONFIG.Twitter.AccessSecret)

	httpClient := job.Config.Client(oauth1.NoContext, token)
	// client := twitter.NewClient(httpClient)

	// 查询帖子信息
	path := TwiApi.UserRetweetLookupEndpoint.UrlID(TwiApi.TwiApiUrl,id)
	resp, _ := httpClient.Get(path)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("QueryActionTypeLike Raw Response Body:\n%v\n", string(body))
	respBody := struct {
		*twi.UserRaw
		Meta *twi.UserRetweetMeta `json:"meta"`
	}{}
	TwiApi.GetLimitRate(resp.Header,resp.Request.URL.String())
	err := json.Unmarshal(body,&respBody)
	if err != nil {
		return err
	}

	// TODO 是否请求下一页
	if respBody.Meta.NextToken != "" {

	}

	if len(respBody.Users) > 0 {
		finishTime := time.Now()
		finishUsers := make([]*twi.UserActionInfo,0)
		err = global.GVA_DB.Raw("select ta.id as tempFinishId," +
			"ta.act_id as actId,ta.template_id as templateId," +
			"tm.address,tm.id,tm.twi_username as twiUsername," +
			"tm.tele_username as teleUsername " +
			"ta.finish_status as tempFinishStatus " +
			"from twi_act_finish_detail as ta LEFT JOIN twi_metamask as tm " +
			"on ta.uid = tm.id ").Scan(&finishUsers).Error
		if err != nil {
			return err
		}
		if len(finishUsers) == 0 {
			return nil
		}
		for _,v := range finishUsers {
			var isDone bool
			for _, vv := range respBody.Users {
				if v.TwiUsername == vv.UserName {
					isDone = true
					break
				}
			}
			// 子任务完成 标记状态
			if isDone && !v.TempFinishStatus{
				err = global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("id = ?",v.TempFinishId).Updates(map[string]interface{}{"finish_time":finishTime,"finish_status":true}).Error
				if err != nil {
					global.GVA_LOG.Error("update status ERR",zap.Error(err))
					return err
				}
				global.GVA_LOG.Info("转发任务完成",zap.String("username",v.TwiUsername))
			}
		}
	}
	return nil
}

// QueryActionTypeLike
// 点赞查询
// id,max_results,pagination_token,expansions,tweet.fields,user.fields
func (job TwiJob) QueryActionTypeLike(template twi.TwiActTemplate) error {
	id := template.ActKey
	// twitterId := global.GVA_CONFIG.Twitter.TwitterId
	token := oauth1.NewToken(global.GVA_CONFIG.Twitter.AccessToken,global.GVA_CONFIG.Twitter.AccessSecret)

	httpClient := job.Config.Client(oauth1.NoContext, token)
	// client := twitter.NewClient(httpClient)

	// 查询帖子信息
	path := TwiApi.TweetLikesEndpoint.UrlID(TwiApi.TwiApiUrl,id)
	resp, _ := httpClient.Get(path)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("QueryActionTypeLike Raw Response Body:\n%v\n", string(body))
	respBody := struct {
		*twi.UserRaw
		Meta *twi.TweetLikesMeta `json:"meta"`
	}{}
	TwiApi.GetLimitRate(resp.Header,resp.Request.URL.String())
	err := json.Unmarshal(body,&respBody)
	if err != nil {
		return err
	}

	// TODO 是否请求下一页
	if respBody.Meta.NextToken != "" {

	}

	if len(respBody.Users) > 0 {
		finishTime := time.Now()
		finishUsers := make([]*twi.UserActionInfo,0)
		err = global.GVA_DB.Raw("select ta.id as tempFinishId," +
			"ta.act_id as actId,ta.template_id as templateId," +
			"tm.address,tm.id,tm.twi_username as twiUsername," +
			"tm.tele_username as teleUsername " +
			"ta.finish_status as tempFinishStatus " +
			"from twi_act_finish_detail as ta LEFT JOIN twi_metamask as tm " +
			"on ta.uid = tm.id ").Scan(&finishUsers).Error
		if err != nil {
			return err
		}
		if len(finishUsers) == 0 {
			return nil
		}
		for _,v := range finishUsers {
			var isDone bool
			for _, vv := range respBody.Users {
				if v.TwiUsername == vv.UserName {
					isDone = true
					break
				}
			}
			// 子任务完成 标记状态
			if isDone && !v.TempFinishStatus{
				err = global.GVA_DB.Model(&twi.TwiActTemplate{}).Where("id = ?",v.TempFinishId).Updates(map[string]interface{}{"finish_time":finishTime,"finish_status":true}).Error
				if err != nil {
					global.GVA_LOG.Error("update status ERR",zap.Error(err))
					return err
				}
				global.GVA_LOG.Info("点赞任务完成",zap.String("username",v.TwiUsername))
			}
		}
	}

	return nil
}

// SyncTwiUserInfo
func (job TwiJob) SyncTwiUserInfo() error {
	unInfo := make([]twi.TwiMetamask,0)
	err := 	global.GVA_DB.Model(&twi.TwiMetamask{}).Where("is_twi_auth = ? ",true).Find(&unInfo).Error
	if err != nil {
		return err
	}
	global.GVA_LOG.Info("auth address ",zap.Int("count",len(unInfo)))

	for _, v:= range unInfo {
		if v.TwiUsername != "" {
			continue
		}
		uid := fmt.Sprintf("addr-%d",v.ID)
		var redisInfo twi.TwiMetamask
		res,err := jwtService.GetOauthInfoTwi(uid)
		if err != nil {
			global.GVA_LOG.Error("异常 已回调绑定 但是获取access-token 失败",zap.Error(err))
			continue
		}
		err = json.Unmarshal([]byte(res),&redisInfo)
		if err != nil {
			global.GVA_LOG.Error("decode access-token 失败",zap.Error(err))
			continue
		}
		token := oauth1.NewToken(redisInfo.AccessToken,redisInfo.AccessSecret)
		global.GVA_LOG.Info("token info",zap.String("token:",token.Token),zap.String("secret",token.TokenSecret))

		httpClient := job.Config.Client(oauth1.NoContext, token)
		// client := twitter.NewClient(httpClient)

		// 查询用户信息
		path := "https://api.twitter.com/2/users/me"
		resp, _ := httpClient.Get(path)
		defer resp.Body.Close()
		body, _ := ioutil.ReadAll(resp.Body)
		fmt.Printf("Raw Response Body:\n%v\n", string(body))
		var resMe ResTwiUserMe
		err = json.Unmarshal(body,&resMe)
		if err != nil {
			global.GVA_LOG.Error("decode 2/users/me 失败",zap.Error(err))
			continue
		}

		TwiApi.GetLimitRate(resp.Header,resp.Request.URL.String())

		redisInfo.TwiId = resMe.Data.Id
		redisInfo.TwiUsername = resMe.Data.Username
		redisInfo.TwiName = resMe.Data.Name
		bytesInfo,err := json.Marshal(redisInfo)
		if err != nil {
			global.GVA_LOG.Error("Marshal 失败",zap.Error(err))
			continue
		}
		err = jwtService.SetOauthInfoTwi(bytesInfo,uid)
		if err != nil {
			global.GVA_LOG.Error("update oauth info redis cache 失败",zap.Error(err))
			continue
		}
		tx := global.GVA_DB.Begin()
		var count int64
		err = tx.Model(&twi.TwiMetamask{}).Where("twi_username = ?",resMe.Data.Username).Count(&count).Error
		if err != nil {
			tx.Rollback()
			global.GVA_LOG.Error("query username is exists 失败",zap.Error(err))
			continue
		}
		// 已绑定
		if count > 0 {
			err = tx.Model(&twi.TwiMetamask{}).Where("id = ?",v.ID).UpdateColumns(map[string]interface{}{"is_twi_auth":false}).Error
			if err != nil {
				global.GVA_LOG.Error("reset is_twi_auth false 失败",zap.Error(err))
				tx.Rollback()
				continue
			}
		} else {
			err = tx.Model(&twi.TwiMetamask{}).Where("address = ?",redisInfo.Address).UpdateColumns(map[string]interface{}{"twi_id":resMe.Data.Id,"twi_name":resMe.Data.Name,"twi_username":resMe.Data.Username}).Error
			if err != nil {
				global.GVA_LOG.Error("update oauth info mysql twi info 失败",zap.Error(err))
				tx.Rollback()
				continue
			}
		}
		tx.Commit()
	}

	return nil
}


type ResTwiUserMe struct {
	Data TwiUserMe `json:"data"`
}

type TwiUserMe struct {
	Id string `json:"id"`
	Name string `json:"name"`
	Username string `json:"username"`
}

