package main

import (
	"container/list"
	"fmt"
	"log/slog"
	"time"

	twitter "github.com/g8rswimmer/go-twitter/v2"
)

/*

处理三种情况：

1. idx 为空；
2. idx 正常匹配
3. idx 没有匹配上
x 4. 到最后也没匹配上，或者超过了多少页。 外面处理；

*/

type Idx struct {
	idx    []UserTask
	newIdx []UserTask
	//taskId string
	List *list.List
}

func NewIdx(i []UserTask) *Idx {
	return &Idx{
		idx:    i,
		newIdx: make([]UserTask, 0, 10),
		List:   list.New(),
	}
}

func (s *Idx) Idx(page []UserTask) (bool, *list.List) {

	if len(s.newIdx) == 0 {
		for k, v := range page {
			s.newIdx = append(s.newIdx, v)
			if k > 5 {
				break
			}
		}
	}

	if s.idx != nil && len(s.idx) == 0 {

		newList := list.New()

		for _, v := range page {
			newList.PushFront(v)
		}

		s.idx = s.newIdx
		s.newIdx = make([]UserTask, 0, 10)

		return true, newList
	}

	//TODO 匹配多个元素，防止用户取消；
	for k, v := range page {

		match := false

		for ik, iv := range s.idx {
			slog.Info("match", "idx", iv.UserId, "page user id", v.UserId, "page user name", v.UserName)
			if v.UserId == iv.UserId {
				match = true
				break
				_, _ = k, ik
			}
		}

		if match {

			newList := s.List
			s.List = list.New()
			//idx
			s.idx = s.newIdx
			s.newIdx = make([]UserTask, 0, 10)

			fmt.Println("newList", "new users", newList.Len())

			return true, newList

		} else {
			s.List.PushFront(v)
		}
	}
	return false, nil
}

type PageUsers struct {
	//cli *Client
	idx *Idx
}

func NewPageUsers(idx *Idx) *PageUsers {

	return &PageUsers{
		//idx: NewIdx(idx),
		idx: idx,
		// cli: cli,
	}
}

type req func(tweetId string, next string) ([]*twitter.UserObj, string, *twitter.RateLimit, error)

/*
TODO 最后一页的标识，没有处理；
*/
func (p *PageUsers) Request(tweetId string, next string, f req) ([]UserTask, error) {

	//users, next, rt, err := p.cli.TweetLikingUsers(tweetId, next)

	users, newNext, rt, err := f(tweetId, next)
	if err != nil {
		return nil, err
	}

	if rt != nil && rt.Remaining == 0 {
		time.Sleep(time.Until(rt.Reset.Time().Add(500 * time.Millisecond)))
	}

	taskUser := userObjectToUserTask(users)

	ok, l := p.idx.Idx(taskUser)

	if ok {

		res := make([]UserTask, 0, l.Len())

		for e := l.Front(); e != nil; e = e.Next() {
			if user, ok := e.Value.(UserTask); ok {
				res = append(res, user)
			}
		}
		return res, nil
	}
	return p.Request(tweetId, newNext, f)

}

func userObjectToUserTask(pageUsers []*twitter.UserObj) []UserTask {

	res := make([]UserTask, 0, len(pageUsers))

	for _, v := range pageUsers {
		res = append(res, UserTask{
			//TaskId   string `json:"task_id"`
			UserId:   v.ID,       //string `json:"user_id"`
			UserName: v.UserName, //string `json:"user_name"`
		})
	}

	return res
}

// func scheduler(tick *time.Ticker) {
// 	for t := range tick.C {
// 		task(t)
// 	}
// }

// func task(t time.Time) {
// 	fmt.Println("hello! printed at ", t)
// }

// func GetFollowTasks() ([]Task, error) {

// 	data, count, err := client.From("tasks").Select("*", "exact", false).
// 		Eq("follow", "true").Neq("follow_stop", "true").
// 		Execute()

// 	if err != nil {
// 		return nil, err
// 	}

// 	res := make([]Task, 0, count)

// 	if err := json.Unmarshal(data, &res); err != nil {
// 		return nil, err
// 	}

// 	return res, nil
// }

// follow, retweet
// const FollowType = "follow"
// const RetweetType = "retweet"
// const FollowType = "follow"

// followers

// const RetweetType = "retweet"

// type FollowerId struct {
// 	Follower
// 	Id        int    `json:"id"`
// 	CreatedAt string `json:"created_at"`
// }

// type Follower struct {
// 	//user_id
// 	UserId   string `json:"user_id"`
// 	Follower string `json:"follower_id"`
// 	UserName string `json:"follower_username"`
// }

// type RetweeterId struct {
// 	Retweeter
// 	Id        int    `json:"id"`
// 	CreatedAt string `json:"created_at"`
// }

// type Retweeter struct {
// 	TweetId           string `json:"tweet_id"`
// 	RetweeterId       string `json:"retweeter_id"`
// 	RetweeterUserName string `json:"retweeter_username"`
// }

// func GetTasksIdx() ([]taskInterface, error) {

// 	tasks, err := QueryAllTask()

// 	if err != nil {
// 		return nil, err
// 	}

// 	res := make([]taskInterface, 0, 10)

// 	for _, task := range tasks {

// 		if task.TaskType == FollowType {

// 			data, count, err := client.From("followers").Select("", "user_id", false).
// 				Eq("user_id", task.TaskId).
// 				Order("id", &postgrest.OrderOpts{
// 					Ascending: false,
// 					// NullsFirst   bool
// 					// ForeignTable string
// 				}).Range(0, 10, "").Execute()

// 			if err != nil {
// 				slog.Error("select * from followers error", err)
// 				return nil, err
// 			}
// 			_ = count

// 			slog.Info("idx data", "user id", task.TaskId, "user name", task.User, "idx", data)

// 			fmt.Println("idx data", string(data))

// 			userRes := make([]FollowerId, 0, 10)

// 			if err := json.Unmarshal(data, &userRes); err != nil {
// 				return nil, err
// 			}

// 			followTask := NewFollowTask(task.TaskId, task.User, task.TaskType)

// 			followTask.Idx = userRes

// 			// if len(userRes) == 0 {
// 			// 	followTask.Init = true
// 			// }

// 			res = append(res, followTask)
// 		}

// 		if task.TaskType == RetweetType {

// 			data, count, err := client.From("retweeters").Select("", "tweet_id", false).
// 				Eq("tweet_id", task.TaskId).
// 				Order("id", &postgrest.OrderOpts{
// 					Ascending: false,
// 					// NullsFirst   bool
// 					// ForeignTable string
// 				}).Range(0, 10, "").Execute()

// 			if err != nil {
// 				slog.Error("select * from retweeters error", err)
// 				return nil, err
// 			}
// 			_ = count

// 			slog.Info("idx data", "tweet id", task.TaskId, "user name", task.User, "idx", data)

// 			fmt.Println("idx data", string(data))

// 			userRes := make([]RetweeterId, 0, 10)

// 			if err := json.Unmarshal(data, &userRes); err != nil {
// 				return nil, err
// 			}

// 			retweetTask := NewRetweetTask(task.TaskId, task.User, task.TaskType)

// 			//followTask := NewFollowTask(task.TaskId, task.User, task.TaskType)

// 			retweetTask.Idx = userRes

// 			// if len(userRes) == 0 {
// 			// 	followTask.Init = true
// 			// }

// 			res = append(res, retweetTask)

// 		}
// 	}

// 	return res, nil
// }

// func FollowersToBackList(done <-chan interface{}, idxss [][]FollowerId) (<-chan *list.List, error) {

// 	scraper := twitterscraper.New()

// 	//err := scraper.Login("Wade_Leeeee", "923881393time")
// 	err := scraper.Login("wuban358369", "123456789T")
// 	if err != nil {
// 		fmt.Println("scraper", err.Error())
// 		return nil, err
// 	}

// 	/*
// 					wuban01@gmail.com

// 					wuban01
// 					1234567890Wuban

// 					1234567890Wuban

// 					// 2346
// 			980b
// 			641a
// 			774d
// 			39fb
// 			9425
// 			c6c5
// 			3140
// 			b469
// 			0b93
// 			d1c6
// 			6101
// 			ef6f
// 			9fb6
// 			ae94
// 			ee6f

// 				//wuban001

// 		wuban01@tutamail.com

// 		1234567890Wuban

// 	*/

// 	scraper3 := twitterscraper.New()

// 	//err = scraper3.Login("tifawe2861@stikezz.com", "123456789T")
// 	//err = scraper3.Login("wuban358369", "123456789T")
// 	err = scraper3.Login("Wade_Leeeee", "923881393time")
// 	if err != nil {
// 		fmt.Println("scraper3", err.Error())
// 		return nil, err
// 	}

// 	fmt.Println("scraper.IsLoggedIn()", scraper.IsLoggedIn())
// 	fmt.Println("scraper3.IsLoggedIn()", scraper3.IsLoggedIn())

// 	userId := "Bitcoin"
// 	next := ""

// 	var backPushPop = list.New()

// 	outStream := make(chan *list.List, 1)

// 	go func() {

// 		//newBegin := true

// 		for _, idxs := range idxss {

// 			newIdxs := make([]FollowerId, 0, len(idxs))

// 			c := true

// 			for {

// 				c = !c

// 				var err error
// 				var users Users

// 				if c {

// 					users, err = FetchFollowers(scraper, userId, next)
// 					if err != nil {
// 						slog.Error("FetchFollowers", err)
// 						time.Sleep(time.Second)
// 						continue
// 					}
// 				} else {
// 					users, err = FetchFollowers(scraper3, userId, next)
// 					if err != nil {
// 						slog.Error("FetchFollowers", err)
// 						time.Sleep(time.Second)
// 						continue
// 					}
// 				}

// 				// users, err := FetchFollowers(scraper, userId, next)
// 				// if err != nil {
// 				// 	slog.Error("FetchFollowers", err)
// 				// 	time.Sleep(time.Second)
// 				// 	continue
// 				// }

// 				fmt.Println("len(users)-----------------", len(users.Profiles))

// 				for k, v := range users.Profiles {
// 					fmt.Println("k", k, "v", v.UserIdAsNumber, v.Username)
// 				}

// 				if len(newIdxs) == 0 {

// 					for k, v := range users.Profiles {
// 						newIdxs = append(newIdxs, FollowerId{
// 							Follower: Follower{
// 								Follower: v.UserIdAsNumber,
// 								UserName: v.Username,
// 							},
// 						})
// 						if k > 5 {
// 							break
// 						}
// 					}
// 				}

// 				profiles, ok := MatchIdx(users, idxs)

// 				fmt.Println("len(profiles)-----------------", len(profiles))

// 				for _, v := range profiles {
// 					backPushPop.PushFront(v)
// 				}

// 				fmt.Printf("!ok %v  users.Next  %s  %d  len(outStream) %d  backPushPop len %d\n", !ok, users.Next, len(users.Next), len(outStream), backPushPop.Len())

// 				time.Sleep(time.Second * 2)

// 				if !ok && len(users.Next) != 0 {
// 					next = users.Next
// 					continue
// 				}

// 				/*
// 					Api has a global limit on how many requests per second are allowed, don’t make requests more than once per 1.5 seconds from one account.
// 					Also each endpoint has its own limits, most of them are 150 requests per 15 minutes.
// 				*/

// 				if backPushPop.Len() == 0 {
// 					next = ""
// 					//time.Sleep(time.Second * 20)
// 					continue
// 				}

// 				idxs = newIdxs
// 				newIdxs = make([]FollowerId, 0, len(idxs))

// 				select {
// 				case <-done:
// 					return
// 				case outStream <- backPushPop:
// 					fmt.Println("case outStream <- backPushPop: ------------")
// 					backPushPop = list.New()
// 					//time.Sleep(time.Second * 20)
// 				}

// 				next = ""
// 				//time.Sleep(time.Second * 20)
// 			}

// 		}

// 	}()

// 	return outStream, nil
// }

// func MatchIdx(data Users, idxs []FollowerId) ([]Profile, bool) {

// 	if len(idxs) == 0 {
// 		return data.Profiles, false
// 	}

// 	for k, v := range data.Profiles {

// 		for _, idx := range idxs {
// 			if v.UserIdAsNumber == idx.Follower.Follower {
// 				return data.Profiles[:k], true
// 			}
// 		}
// 	}

// 	return data.Profiles, false
// }
