package service

import (
	"fmt"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/elastic/eapi"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/utility"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"os"
	"strings"
)

// Chapter 章节服务
var Chapter = new(sChapter)

type sChapter struct{}

//func (s *sChapter) OrdinaryList(ctx *gin.Context, req forms.ChapterOrdinaryListReq) (resp serializer.Response) {
//	type passData struct {
//		Id         int32  `json:"id"`
//		Name       string `json:"name"`
//		RoomCount  int32  `json:"roomCount"`
//		Count      int64  `json:"count"`
//		Difficulty int64  `json:"difficulty"`
//		Pass       bool   `json:"pass"`
//		IsActivity bool   `json:"isActivity"`
//	}
//
//	DB, err := player.GetDBByUserId(req.PlayerId)
//	if err != nil {
//		return serializer.Err(consts.CodeParamErr, "GetDBByUserId err", err)
//	}
//
//	var (
//		p         = query.Use(config.GDBGroup[DB]).PlayerMaterial
//		passDatas []passData
//		models    forms.ListRes
//	)
//	material, err := p.WithContext(ctx).Where(p.Playerid.Eq(req.PlayerId)).First()
//	if err != nil {
//		return serializer.Err(consts.CodeParamErr, "查询出错 Find", err)
//	}
//
//	if material == nil || material.ID == 0 || material.PassRoom == "null" {
//		return serializer.Suc(models)
//	}
//
//	if err := json.Unmarshal([]byte(material.PassRoom), &passDatas); err != nil {
//		return serializer.Err(consts.CodeParamErr, "Unmarshal err", err)
//	}
//
//	tmp := make([]passData, 0)
//	for k, v := range passDatas {
//		if v.Id == 0 || v.Id > 99 {
//			continue
//		}
//		data := gmdata.GetChapterById(v.Id)
//		if data == nil {
//			data = &gmdata.Chapter{
//				Name: `未知`,
//			}
//		}
//		passDatas[k].Name = data.Name
//		passDatas[k].RoomCount = data.RoomCount
//		tmp = append(tmp, passDatas[k])
//	}
//
//	// 使用自定义的 Less 函数来指定排序规则
//	sort.SliceStable(tmp, func(i, j int) bool {
//		if tmp[i].Id != tmp[j].Id {
//			return tmp[i].Id < tmp[j].Id // 根据 Id 升序排列
//		}
//		return tmp[i].Difficulty < tmp[j].Difficulty // 如果 Id 相同，则根据 Difficulty 升序排列
//	})
//
//	models.List = tmp
//
//	return serializer.Suc(models)
//}

//func (s *sChapter) ActivityList(ctx *gin.Context, req forms.ChapterActivityListReq) (resp serializer.Response) {
//	type passData struct {
//		Id               int32   `json:"id"`
//		Difficulty       int32   `json:"difficulty"`
//		DifficultyName   string  `json:"difficultyName"`
//		Name             string  `json:"name"`
//		Degree           int32   `json:"degree"`
//		RewardMulti      float64 `json:"rewardMulti"`
//		RewardEffectTime int64   `json:"rewardEffectTime"`
//		ChallengeCount   int64   `json:"challenge_count"`
//		ClearanceCount   int64   `json:"clearance_count"`
//		FailCount        int64   `json:"fail_count"`
//	}
//
//	DB, err := player.GetDBByUserId(req.PlayerId)
//	if err != nil {
//		return serializer.Err(consts.CodeParamErr, "GetDBByUserId err", err)
//	}
//
//	var (
//		c         = query.Use(config.DB).Chapter
//		passDatas []passData
//		models    forms.ListRes
//		z         = query.Use(config.GDBGroup[DB]).ZoneActivity
//	)
//	chapters, err := c.WithContext(ctx).Where(c.PlayerID.Eq(req.PlayerId)).Find()
//	if err != nil {
//		return serializer.Err(consts.CodeParamErr, "查询出错 Find", err)
//	}
//
//	if len(chapters) == 0 {
//		return serializer.Suc(models)
//	}
//
//	zone, err := z.WithContext(ctx).Where(z.Playerid.Eq(req.PlayerId)).First()
//	if err != nil {
//		return serializer.Err(consts.CodeParamErr, "查询出错 Find", err)
//	}
//
//	// BonusProperties 加成属性
//	type BonusProperties struct {
//		DifScale         int     `json:"difScale"`         // 难度系数
//		RewardMulti      float64 `json:"rewardMulti"`      // 奖励倍数
//		RewardEffectTime int64   `json:"rewardEffectTime"` // 奖励倍数生效时间
//	}
//
//	bonusProperties := make(map[string]*BonusProperties)
//	//difficulty := make(map[string]int32)
//	if zone != nil {
//		if err = json.Unmarshal([]byte(zone.BonusProperties), &bonusProperties); err != nil {
//			return serializer.Err(consts.CodeParamErr, "Unmarshal err", err)
//		}
//	}
//
//	logrus.Warnf("bonusProperties:%+v", bonusProperties)
//
//	//chapterIds := []int64{100, 101, 102, 103}
//	//var difficultys = []int32{0, 1, 2}
//
//	for _, v := range chapters {
//		var data = gmdata.GetChapterById(v.ChapterID)
//		if data == nil {
//			data = &gmdata.Chapter{
//				Name: `未知`,
//			}
//		}
//
//		//var ds = []int32{0, 1, 2}
//		//if v.ChapterID == 103 {
//		//	ds = []int32{0}
//		//}
//		//
//		//for _, difficulty := range ds {
//		//
//		//
//		//}
//
//		bs, ok := bonusProperties[fmt.Sprintf("%v_%v", v.ChapterID, v.Difficulty)]
//		if ok {
//			passDatas = append(passDatas, passData{
//				Id:               v.ChapterID,
//				Difficulty:       v.Difficulty,
//				DifficultyName:   gmdata.GetDifficultName(int64(v.Difficulty)),
//				Name:             data.Name,
//				Degree:           int32(bs.DifScale),
//				RewardMulti:      bs.RewardMulti,
//				RewardEffectTime: bs.RewardEffectTime,
//				ChallengeCount:   int64(v.ClearanceCount + v.FailCount),
//				ClearanceCount:   int64(v.ClearanceCount),
//				FailCount:        int64(v.FailCount),
//			})
//		} else {
//			// 没有数据视为没有参与过，直接不显示
//			//passDatas = append(passDatas, passData{
//			//	Id:               v.ChapterID,
//			//	Difficulty:       difficulty,
//			//	Name:             data.Name,
//			//	Degree:           100, // 这里写死了100，其实有的初始值并不是100，需要知道
//			//	RewardMulti:      1,
//			//	RewardEffectTime: 0,
//			//	ChallengeCount:   int64(v.ClearanceCount + v.FailCount),
//			//	ClearanceCount:   int64(v.ClearanceCount),
//			//	FailCount:        int64(v.FailCount),
//			//})
//		}
//
//	}
//
//	// 远征
//	var (
//		cf = query.Use(config.GDBGroup[DB]).Climbfloor
//	)
//	cfd, _ := cf.WithContext(ctx).Where(cf.Playerid.Eq(req.PlayerId)).First()
//	//if err != nil {
//	//	return serializer.Err(consts.CodeParamErr, "查询出错 Climbfloor Find", err)
//	//}
//
//	if cfd == nil {
//		passDatas = append(passDatas, passData{
//			Id:             105,
//			Name:           "远征",
//			Degree:         0,
//			DifficultyName: gmdata.GetDifficultName(int64(0)),
//			//ChallengeCount: int64(v.ClearanceCount + v.FailCount),
//			//ClearanceCount: int64(v.ClearanceCount),
//			//FailCount:      int64(v.FailCount),
//		})
//	} else {
//		passDatas = append(passDatas, passData{
//			Id:             105,
//			Name:           "远征",
//			Degree:         cfd.MaxFloor,
//			DifficultyName: gmdata.GetDifficultName(int64(0)),
//			//ChallengeCount: int64(v.ClearanceCount + v.FailCount),
//			//ClearanceCount: int64(v.ClearanceCount),
//			//FailCount:      int64(v.FailCount),
//		})
//	}
//
//	models.List = passDatas
//
//	return serializer.Suc(models)
//}

func (s *sChapter) doReconnectFromDB(ctx *gin.Context, params forms.ChapterReconnectReq, chapterId, difficulty int32, isNew bool) (count, userCount int64, err error) {
	type Result struct {
		TotalCount int64 `gorm:"total_count"`
		UserCount  int64 `gorm:"user_count"`
	}
	begin, end, _ := utility.GetBeginAndEndOfDay2(params.Day, params.EndDay)
	end = end + 1
	table := model.GetChapterTable2(chapterId)
	var (
		q  = query.Use(config.DB).ChapterLog.Table(table)
		db = q.UnderlyingDB()
	)

	db = db.Where("event_id = 2 and extra like '%0%' and difficulty = ? and event_at >= ? and event_at <=  ?", difficulty, begin, end)

	if params.ServerId > 0 {
		db = db.Where("server_id = ?", params.ServerId)
	}

	switch params.ChannelId {
	case consts.ChannelIdNone:
	// 不选择渠道
	case consts.ChannelIdAllAdv, consts.ChannelIdAllWx, consts.ChannelIdAllTT:
		// 所有广告渠道
		db = db.Where("channel_id in (?)", Channel.GetIdsByType(params.ChannelId))
	default:
		// 选择指定渠道
		db = db.Where("channel_id = ?", params.ChannelId)
	}
	res := make([]*Result, 0)
	if isNew {
		err = db.Select("count(*) AS total_count, count( DISTINCT user_id ) AS user_count, DATE (FROM_UNIXTIME( user_created_at )) AS d").Where("user_created_at >= ? and  user_created_at <= ?", begin, end).Group("d").Find(&res).Error
	} else {
		err = db.Select("count(*) AS total_count, count( DISTINCT user_id ) AS user_count").Find(&res).Error
	}
	if err != nil {
		logrus.Errorf("查询出错：%+v", err)
		if strings.Contains(err.Error(), "1146") {
			createSql := "CREATE TABLE IF NOT EXISTS `%s` (`id` bigint unsigned NOT NULL AUTO_INCREMENT,`channel_id` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '渠道ID',`flag` int DEFAULT '0',`user_id` bigint unsigned NOT NULL COMMENT '用户id',`server_id` int NOT NULL DEFAULT '1' COMMENT '服务器ID',`event_id` tinyint unsigned NOT NULL COMMENT '埋点id',`chapter_id` smallint unsigned NOT NULL COMMENT '关卡id',`difficulty` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '困难度',`room_id` bigint NOT NULL COMMENT '房间id',`user_created_at` int unsigned NOT NULL COMMENT '用户注册时间',`event_at` int unsigned NOT NULL COMMENT '埋点事件触发的时间',`event_at_ns` bigint unsigned NOT NULL,`token` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登陆的token',`extra` text COLLATE utf8mb4_general_ci COMMENT '其他参数',PRIMARY KEY (`id`),UNIQUE KEY `user_event_ns` (`user_id`,`event_at_ns`),KEY `created_chapter_event_event_at_idx` (`user_created_at`,`chapter_id`,`event_id`,`event_at`),KEY `event_id_event_at_idx` (`event_id`,`event_at`),KEY `server_id` (`server_id`),KEY `channel_id` (`channel_id`),KEY `idx_event_id` (`event_id`) USING BTREE,KEY `server_id_difficulty_user_id_event_id_extra_index` (`server_id`,`difficulty`,`user_id`,`event_id`),KEY `chapter_logs_100_event_at_index` (`event_at`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关卡信息埋点日志';"
			if err := q.UnderlyingDB().Exec(fmt.Sprintf(createSql, table)).Error; err != nil {
				logrus.Errorf("创建表%s错误：%+v", table, err)
			}
		}
		return 0, 0, err
	}
	for _, v := range res {
		count += v.TotalCount
		userCount += v.UserCount
	}
	return
}

func (s *sChapter) doReconnect(ctx *gin.Context, params forms.ChapterReconnectReq, chapterId, difficulty int32, isNew bool) (count, userCount int64, err error) {
	begin, end, _ := utility.GetBeginAndEndOfDay2(params.Day, params.EndDay)
	end = end + 1

	index := fmt.Sprintf("%s%s", os.Getenv("ELASTIC_TOPIC"), model.GetChapterTable2(chapterId))

	var (
		mustNot []eapi.M
		where   eapi.M
	)

	must := []eapi.M{
		{
			"term": eapi.M{
				"event_id": "2",
			},
		},
		{
			"match": eapi.M{
				"extra": "0",
			},
		},
		{
			"term": eapi.M{
				"chapter_id": chapterId,
			},
		},
		{
			"term": eapi.M{
				"difficulty": difficulty,
			},
		},
		{
			"range": eapi.M{
				"event_at": eapi.M{
					"gte": begin,
					"lte": end,
				},
			},
		},
	}

	if params.ServerId > 0 {
		must = append(must, eapi.M{
			"term": eapi.M{
				"server_id": params.ServerId,
			},
		})
	}

	switch params.ChannelId {
	case consts.ChannelIdNone:
	// 不选择渠道
	case consts.ChannelIdAllAdv, consts.ChannelIdAllWx, consts.ChannelIdAllTT:
		// 所有广告渠道
		must = append(must, eapi.M{
			"terms": eapi.M{
				"channel_id": Channel.GetIdsByType(params.ChannelId),
			},
		})
	default:
		// 选择指定渠道
		must = append(must, eapi.M{
			"term": eapi.M{
				"channel_id": params.ChannelId,
			},
		})
	}

	//if params.ChannelId != "" {
	//	if params.ChannelId == "1" {
	//		mustNot = append(mustNot, eapi.M{
	//			"term": eapi.M{
	//				"channel_id": "0",
	//			},
	//		})
	//	} else {
	//		must = append(must, eapi.M{
	//			"term": eapi.M{
	//				"channel_id": params.ChannelId,
	//			},
	//		})
	//	}
	//
	//}

	// 新用户
	if isNew {
		// 同一天
		if begin+86400 == end {
			must = append(must, eapi.M{
				"range": eapi.M{
					"user_created_at": eapi.M{
						"gte": begin,
						"lte": end,
					},
				},
			})
		} else {
			// 多天的，分析每天的新用户
			for i := begin; i < end; i += 86400 {
				var newMust = must
				newMust = append(newMust, eapi.M{
					"range": eapi.M{
						"user_created_at": eapi.M{
							"gte": i,
							"lte": i + 86400,
						},
					},
				})

				if len(mustNot) > 0 {
					where = eapi.M{
						"query": eapi.M{
							"bool": eapi.M{
								"must":     newMust,
								"must_not": mustNot,
							},
						},
					}
				} else {
					where = eapi.M{
						"query": eapi.M{
							"bool": eapi.M{
								"must": newMust,
							},
						},
					}
				}

				res, err := eapi.Count(ctx, index, where)
				if err != nil {
					return 0, 0, err
				}

				if res > 0 {
					count += res
				}

				res2, err := eapi.Cardinality(ctx, index, where, "user_id")
				if err != nil {
					return 0, 0, err
				}

				if res2 > 0 {
					userCount += res2
				}

			}

			return
		}

	}

	if len(mustNot) > 0 {
		where = eapi.M{
			"query": eapi.M{
				"bool": eapi.M{
					"must":     must,
					"must_not": mustNot,
				},
			},
		}
	} else {
		where = eapi.M{
			"query": eapi.M{
				"bool": eapi.M{
					"must": must,
				},
			},
		}
	}

	//logrus.Warnf("doReconnect index:%v\n where:%v\n", index, utility.DumpToJSON(where))

	res, err := eapi.Count(ctx, index, where)
	if err != nil {
		return 0, 0, err
	}

	res2, err := eapi.Cardinality(ctx, index, where, "user_id")
	if err != nil {
		return 0, 0, err
	}

	return res, res2, nil
}

//func (s *sChapter) Reconnect(ctx *gin.Context, params forms.ChapterReconnectReq) (resp serializer.Response) {
//	chapterMap := gmdata.GetChaptersMap()
//	var (
//		wg    sync.WaitGroup
//		errCh = make(chan error, len(chapterMap))
//	)
//
//	list := make([]forms.ChapterReconnectItem, 0)
//	for _, v := range chapterMap {
//		wg.Add(1)
//		go func(v *gmdata.Chapter) {
//			defer wg.Done()
//			//count, users, err := s.doReconnect(ctx, params, int32(v.ID), int32(v.Difficulty), false)
//			count, users, err := s.doReconnectFromDB(ctx, params, int32(v.ID), int32(v.Difficulty), false)
//			if err != nil {
//				errCh <- err
//				return
//			}
//
//			//newCount, newUsers, err := s.doReconnect(ctx, params, int32(v.ID), int32(v.Difficulty), true)
//			newCount, newUsers, err := s.doReconnectFromDB(ctx, params, int32(v.ID), int32(v.Difficulty), true)
//			if err != nil {
//				errCh <- err
//				return
//			}
//
//			list = append(list, forms.ChapterReconnectItem{
//				Id:              len(list),
//				ChapterId:       int(v.ID),
//				Chapter:         Dash.GetChapterName(v.ID, v.Difficulty),
//				DifficultyIndex: int(v.Difficulty),
//				Difficulty:      gmdata.GetDifficultName(v.Difficulty),
//				DieCount:        count,
//				DieUserCount:    users,
//				NewDieCount:     newCount,
//				NewDieUserCount: newUsers,
//			})
//		}(v)
//	}
//
//	wg.Wait()
//
//	select {
//	case err1 := <-errCh:
//		return serializer.Err(consts.CodeParamErr, err1.Error(), err1)
//	default:
//
//	}
//
//	for k, v := range list {
//		list[k].Index = v.ChapterId*1000 + v.DifficultyIndex
//	}
//	sort.Sort(forms.ChapterReconnectItemSlice(list))
//
//	pageCount := int64(len(list))
//	models := new(forms.ChapterReconnectRespData)
//	models.Page = params.Page
//	models.PerPage = params.PerPage
//	models.PageCount = int64(math.Ceil(float64(pageCount) / float64(params.PerPage)))
//
//	startInx := (models.Page - 1) * models.PerPage
//	endInx := (models.Page) * models.PerPage
//	if startInx < 0 {
//		startInx = 0
//	}
//	if endInx > pageCount {
//		endInx = pageCount
//	}
//	subList := list[startInx:endInx]
//
//	models.List = subList
//	return serializer.Suc(models)
//}
