package module

import (
	"database/sql"
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
)

type UserTopicMysqlDao struct {
	db             *sql.DB
	userTopicTable string
	topicItemTable string
	configs        map[string]interface{}
	itemType       string
	recallName     string
	total          int
	topicNum       int
}

const (
	SQL_User_Topic_Filter = "SELECT favorite_topic FROM %s WHERE user_id='%s'"
	SQL_Topic_Item_Filter = "SELECT article_ids FROM %s WHERE topic='%s' ORDER BY publish_time DESC, value DESC LIMIT %d"
	User_Topic_Table      = "pai_recommend_recall_v2_user_topic_list_result"
	Topic_Item_Table      = "pai_recommend_recall_v2_topic_article_list"
)

func NewUserTopicMysqlDao(config recconf.RecallConfig) *UserTopicMysqlDao {
	dao := &UserTopicMysqlDao{
		itemType:       config.ItemType,
		recallName:     config.Name,
		total:          1000,
		topicNum:       5,
		userTopicTable: config.UserTopicDaoConf.UserTopicTable,
		topicItemTable: config.UserTopicDaoConf.TopicItemTable,
	}
	mysql, err := mysqldb.GetMysql(config.UserTopicDaoConf.MysqlName)
	if err != nil {
		log.Error(fmt.Sprintf("%v", err))
		return nil
	}
	dao.db = mysql.DB
	return dao
}

type topicInfo struct {
	topic string
	value float64
	count int
}

func (d *UserTopicMysqlDao) ListItemsByUser(user *User, context *context.RecommendContext) (ret []*Item) {
	uid := string(user.Id)
	sql := fmt.Sprintf(SQL_User_Topic_Filter, d.userTopicTable, uid)
	rows, err := d.db.Query(sql)
	if err != nil {
		log.Error(fmt.Sprintf("requestId=%s\tmodule=UserTopicMysqlDao\tuid=%s\terror=%v", context.RecommendId, uid, err))
		return
	}
	topics := make([]*topicInfo, 0)
	for rows.Next() {
		var comm string
		if err := rows.Scan(&comm); err == nil {
			idList := strings.Split(comm, ",")
			for _, id := range idList {
				tv := strings.Split(id, ":")
				if len(tv) == 2 {
					f, err := strconv.ParseFloat(tv[1], 64)
					if err != nil || f == float64(0) {
						f = float64(0.5)
					}

					info := topicInfo{
						topic: tv[0],
						value: f,
					}
					topics = append(topics, &info)
				}
			}
		}
	}
	rows.Close()

	if len(topics) == 0 {
		return
	}

	if len(topics) > d.topicNum {
		rand.Shuffle(len(topics), func(i, j int) {
			topics[i], topics[j] = topics[j], topics[i]
		})

		topics = topics[:d.topicNum]
	}
	totalValue := float64(0)
	for _, topic := range topics {
		totalValue += topic.value
	}
	for _, topic := range topics {
		topic.count = int((topic.value / totalValue) * float64(d.total))
		result, err := func(info *topicInfo) ([]*Item, error) {
			result := make([]*Item, 0)
			sql := fmt.Sprintf(SQL_Topic_Item_Filter, d.topicItemTable, info.topic, info.count)
			rows, err := d.db.Query(sql)
			if err != nil {
				log.Error(fmt.Sprintf("requestId=%s\tmodule=UserTopicMysqlDao\tsql=%s\terror=%v", context.RecommendId, sql, err))
				return result, err
			}
			for rows.Next() {
				var ids string
				if err := rows.Scan(&ids); err != nil {
					log.Error(fmt.Sprintf("requestId=%s\tmodule=UserTopicMysqlDao\terror=%v", context.RecommendId, err))
					continue
				}

				item := &Item{
					Id:         ItemId(ids),
					ItemType:   d.itemType,
					RetrieveId: d.recallName,
				}
				result = append(result, item)
			}
			rows.Close()

			return result, nil
		}(topic)

		if err == nil {
			ret = append(ret, result...)
		}
	}

	/**
	cpuCount := len(topics)

	itemIdCh := make(chan *topicInfo, cpuCount)
	for _, info := range topics {
		itemIdCh <- info
	}

	itemCh := make(chan []*Item, cpuCount)
	for i := 0; i < cpuCount; i++ {
		go func() {
			result := make([]*Item, 0)
		LOOP:
			for {
				select {
				case info := <-itemIdCh:
					sql := fmt.Sprintf(SQL_Topic_Item_Filter, d.topicItemTable, info.topic, info.count)
					rows, err := d.db.Query(sql)
					if err != nil {
						log.Error(fmt.Sprintf("requestId=%s\tmodule=UserTopicMysqlDao\tsql=%s\terror=%v", context.RecommendId, sql, err))
						goto LOOP
					}
					for rows.Next() {
						var ids string
						if err := rows.Scan(&ids); err != nil {
							log.Error(fmt.Sprintf("requestId=%s\tmodule=UserTopicMysqlDao\terror=%v", context.RecommendId, err))
							continue
						}

						item := &Item{
							Id:         ItemId(ids),
							ItemType:   "article",
							RetrieveId: "user_topic",
						}
						result = append(result, item)
					}
					rows.Close()
				default:
					goto DONE
				}
			}
		DONE:
			itemCh <- result
		}()
	}
	for i := 0; i < cpuCount; i++ {
		items := <-itemCh
		ret = append(ret, items...)
	}
	close(itemCh)
	close(itemIdCh)
	**/
	return
}
