package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/dghubble/oauth1"
	twitter "github.com/g8rswimmer/go-twitter/v2"
	twitterscraper "github.com/imperatrona/twitter-scraper"
	"golang.org/x/time/rate"
)

/*

GET /2/tweets/:id/liking_users
5 requests / 15 mins
PER USER
25 requests / 15 mins
PER APP


GET /2/users/:id/liked_tweets
5 requests / 15 mins
PER APP
5 requests / 15 mins
PER USER

*/

/*
GET /2/tweets/:id/retweeted_by
5 requests / 15 mins
PER APP
5 requests / 15 mins
PER USER

*/

var LikeRateLimit *rate.Limiter = rate.NewLimiter(rate.Every(3*time.Minute), 1)
var RetweetRateLimit *rate.Limiter = rate.NewLimiter(rate.Every(5*time.Minute), 1)

type authorize struct {
	Token string
}

func (a authorize) Add(req *http.Request) {
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Token))
}

type Client struct {
	*twitter.Client

	Ratelimiter *rate.Limiter

	RetweeterRatelimiter  *rate.Limiter
	LikingUserRatelimiter *rate.Limiter

	Scraper *twitterscraper.Scraper
}

type Config struct {
	ApiKey            string `json:"api_key"`
	ApiKeySecrect     string `json:"api_key_secret"`
	AccessToken       string `json:"access_token"`
	AccessTokenSecret string `json:"access_token_secret"`
	Token             string `json:"token"`
}

// func NewFollowClient() *Client {
// 	return &Client{
// 		Scraper: twitterscraper.New(),
// 	}
// }

func NewLikeClient(cfg Config) *Client {
	return NewClient(cfg, LikeRateLimit)
}

func NewRetweeterClient(cfg Config) *Client {
	return NewClient(cfg, RetweetRateLimit)
}

func NewClient(cfg Config, rts *rate.Limiter) *Client {

	//func NewClient(cfg Config) *Client {

	//twitterAPIKey := "lVnj6Ox9HPcI4LwArSSYU7Pba"                                //os.Getenv("TWITTER_API_KEY")
	//twitterAPIKeySecret := "QMSnWG4QwyXWBVW2hQazzxhw9cSjd32CDfXGkg2DEaUUdscCRZ" //os.Getenv("TWITTER_API_KEY_SECRET")

	oauth1Config := oauth1.NewConfig(cfg.ApiKey, cfg.ApiKeySecrect)

	//twitterAccessToken := "1783145144700874752-TqHrsFUL20fEz4nz71yYlYVihkGmZn"  //os.Getenv("TWITTER_ACCESS_TOKEN")
	//twitterAccessTokenSecret := "QDmtDfsiMigTJk1iqoyq8zCHNQJq5zCeC560NH9T5yUZl" //os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")

	twitterHttpClient := oauth1Config.Client(oauth1.NoContext, &oauth1.Token{
		Token:       cfg.AccessToken,
		TokenSecret: cfg.AccessTokenSecret,
	})

	twitterClient := &twitter.Client{
		Authorizer: authorize{
			Token: cfg.Token,
			//Token: "AAAAAAAAAAAAAAAAAAAAAEaPvQEAAAAAWDyrWaIbZHPYeg3ifnvXWdlylvs%3D7XFIO4y2HA0suNxLv570AsaIfmWD4x6XB64zHd9saEqVAhuTMq",
		},
		Client: twitterHttpClient, //http.DefaultClient,
		Host:   "https://api.twitter.com",
	}

	return &Client{
		Client:      twitterClient,
		Ratelimiter: rts,
		//RetweeterRatelimiter:  RetweetRateLimit,
		//LikingUserRatelimiter: LikeRateLimit,
	}

}

func NewOAuth2Client0817() *Client {

	twitterAPIKey := "lVnj6Ox9HPcI4LwArSSYU7Pba"                                //os.Getenv("TWITTER_API_KEY")
	twitterAPIKeySecret := "QMSnWG4QwyXWBVW2hQazzxhw9cSjd32CDfXGkg2DEaUUdscCRZ" //os.Getenv("TWITTER_API_KEY_SECRET")

	oauth1Config := oauth1.NewConfig(twitterAPIKey, twitterAPIKeySecret)

	twitterAccessToken := "1783145144700874752-TqHrsFUL20fEz4nz71yYlYVihkGmZn"  //os.Getenv("TWITTER_ACCESS_TOKEN")
	twitterAccessTokenSecret := "QDmtDfsiMigTJk1iqoyq8zCHNQJq5zCeC560NH9T5yUZl" //os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")

	twitterHttpClient := oauth1Config.Client(oauth1.NoContext, &oauth1.Token{
		Token:       twitterAccessToken,
		TokenSecret: twitterAccessTokenSecret,
	})

	twitterClient := &twitter.Client{
		Authorizer: authorize{
			Token: "AAAAAAAAAAAAAAAAAAAAAEaPvQEAAAAAWDyrWaIbZHPYeg3ifnvXWdlylvs%3D7XFIO4y2HA0suNxLv570AsaIfmWD4x6XB64zHd9saEqVAhuTMq",
		},
		Client: twitterHttpClient, //http.DefaultClient,
		Host:   "https://api.twitter.com",
	}

	return &Client{
		Client: twitterClient,
	}
}

func (c *Client) Retweeters(tweetId string, next string) ([]*twitter.UserObj, string, *twitter.RateLimit, error) {

	// ctx is generated here only to use with Ratelimiter
	// TODO: Fix performance by removing unneeded allocaton here

	ctx := context.Background()
	err := c.Ratelimiter.Wait(ctx) // This is a blocking call.

	//err := c.RetweeterRatelimiter.Wait(ctx) // This is a blocking call.
	if err != nil {
		return nil, "", nil, err
	}

	opts := twitter.UserRetweetLookupOpts{
		Expansions:      []twitter.Expansion{twitter.ExpansionPinnedTweetID},
		PaginationToken: next,
	}

	userResponse, err := c.Client.UserRetweetLookup(context.Background(), tweetId, opts)
	if err != nil {
		return nil, "", nil, err
	}

	return userResponse.Raw.Users, userResponse.Meta.NextToken, userResponse.RateLimit, nil

}

func (c *Client) TweetLikingUsers(tweetId string, next string) ([]*twitter.UserObj, string, *twitter.RateLimit, error) {

	// ctx is generated here only to use with Ratelimiter
	// TODO: Fix performance by removing unneeded allocaton here

	ctx := context.Background()
	err := c.Ratelimiter.Wait(ctx) // This is a blocking call.
	//err := c.LikingUserRatelimiter.Wait(ctx) // This is a blocking call.
	if err != nil {
		return nil, "", nil, err
	}

	opts := twitter.TweetLikesLookupOpts{
		Expansions:      []twitter.Expansion{twitter.ExpansionPinnedTweetID},
		TweetFields:     []twitter.TweetField{twitter.TweetFieldCreatedAt, twitter.TweetFieldConversationID, twitter.TweetFieldAttachments},
		PaginationToken: next,
	}

	fmt.Println("Callout to tweet like lookup callout")

	tweetResponse, err := c.Client.TweetLikesLookup(context.Background(), tweetId, opts)
	if err != nil {
		return nil, "", nil, err
	}

	return tweetResponse.Raw.Users, tweetResponse.Meta.NextToken, tweetResponse.RateLimit, nil

}

func (c *Client) Me() (map[string]*twitter.UserDictionary, error) {

	// ctx is generated here only to use with Ratelimiter
	// TODO: Fix performance by removing unneeded allocaton here
	if c.Ratelimiter != nil {
		ctx := context.Background()
		err := c.Ratelimiter.Wait(ctx) // This is a blocking call.
		if err != nil {
			return nil, err
		}
	}

	opts := twitter.UserLookupOpts{
		Expansions: []twitter.Expansion{twitter.ExpansionPinnedTweetID},
	}

	userResponse, err := c.Client.AuthUserLookup(context.Background(), opts)

	if err != nil {
		return nil, err
	}

	dictionaries := userResponse.Raw.UserDictionaries()

	return dictionaries, nil
}

/*
	先不考虑单个app cli异常；

	确认根据数量 交替，还是根据时间；优先时间；
*/

type TwoClient struct {
	cli1 *Client
	cli2 *Client
	//queue chan *Client
	count int
}

func NewTwoClient() {

	//先确认，周期是怎么计算的，确定能不能交叉；
}

func (c *TwoClient) Retweeters(tweetId string, next string) ([]*twitter.UserObj, string, *twitter.RateLimit, error) {

	//for c := range c.queue {
	//	return c.Retweeters(tweetId, next)
	//}

	if c.count < 6 {
		return c.cli1.Retweeters(tweetId, next)
	}

	return c.cli1.Retweeters(tweetId, next)

	//return nil, "", nil, fmt.Errorf("two client queue has closed")
}

func (c *TwoClient) TweetLikingUsers(tweetId string, next string) ([]*twitter.UserObj, string, *twitter.RateLimit, error) {

	return nil, "", nil, fmt.Errorf("two client queue has closed")

}

func (c *TwoClient) Me() (map[string]*twitter.UserDictionary, error) {

	// for c := range c.queue {
	// 	return c.Me()
	// }

	return nil, fmt.Errorf("two client queue has closed")
}

/*

func NewOAuth2ClientSelf() *Client {

	twitterAPIKey := "Ufhj9NggOmRb61LTYUinaDHws"                                //os.Getenv("TWITTER_API_KEY")
	twitterAPIKeySecret := "IfsfhxpyKqmYaEkyB89uH5tT8Ma77FJqrB0BsFN7uUnNX0UZ4B" //os.Getenv("TWITTER_API_KEY_SECRET")

	oauth1Config := oauth1.NewConfig(twitterAPIKey, twitterAPIKeySecret)

	twitterAccessToken := "1823984946710765569-9Nj7JZaBKQQiTnSyFiOBC3ADnepQqR"  //os.Getenv("TWITTER_ACCESS_TOKEN")
	twitterAccessTokenSecret := "MltXbwW8Rrb6DJKJo3qnG3lHMUWZ6ILCcqFnujfHrZ875" //os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")

	twitterHttpClient := oauth1Config.Client(oauth1.NoContext, &oauth1.Token{
		Token:       twitterAccessToken,
		TokenSecret: twitterAccessTokenSecret,
	})

	twitterClient := &twitter.Client{
		Authorizer: authorize{
			Token: "AAAAAAAAAAAAAAAAAAAAAD6AvQEAAAAApN304Hsb89%2FMWG2RoLfSEgb2RS0%3DVQin0pVyPOsOBkCPFoy4wQKOXh3nBvoxMqQ6dc7ulaJ2anvoCm",
		},
		Client: twitterHttpClient,
		Host:   "https://api.twitter.com",
	}

	return &Client{
		Client: twitterClient,
	}
}


func NewOAuth2Client0816() *Client {

	twitterAPIKey := "lVnj6Ox9HPcI4LwArSSYU7Pba"                                //os.Getenv("TWITTER_API_KEY")
	twitterAPIKeySecret := "QMSnWG4QwyXWBVW2hQazzxhw9cSjd32CDfXGkg2DEaUUdscCRZ" //os.Getenv("TWITTER_API_KEY_SECRET")

	oauth1Config := oauth1.NewConfig(twitterAPIKey, twitterAPIKeySecret)

	twitterAccessToken := "1783145144700874752-TqHrsFUL20fEz4nz71yYlYVihkGmZn"  //os.Getenv("TWITTER_ACCESS_TOKEN")
	twitterAccessTokenSecret := "QDmtDfsiMigTJk1iqoyq8zCHNQJq5zCeC560NH9T5yUZl" //os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")

	twitterHttpClient := oauth1Config.Client(oauth1.NoContext, &oauth1.Token{
		Token:       twitterAccessToken,
		TokenSecret: twitterAccessTokenSecret,
	})

	twitterClient := &twitter.Client{
		Authorizer: authorize{
			Token: "AAAAAAAAAAAAAAAAAAAAAEaPvQEAAAAAWDyrWaIbZHPYeg3ifnvXWdlylvs%3D7XFIO4y2HA0suNxLv570AsaIfmWD4x6XB64zHd9saEqVAhuTMq",
		},
		Client: twitterHttpClient,
		Host:   "https://api.twitter.com",
	}

	return &Client{
		Client: twitterClient,
	}
}



*/
