package main

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"time"

	_ "code.wuban.net.cn/odysseus/twitter_syncer/docs"
	// docs are generated by Swag CLI, you have to import them.
	// replace with your own docs folder, usually "github.com/username/reponame/docs"
	//_ "github.com/gofiber/swagger/example/docs"

	"github.com/supabase-community/postgrest-go"
	"github.com/supabase-community/supabase-go"
)

var client *supabase.Client

func init() {

	//var API_URL = "http://43.198.54.207:8000"
	//var API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
	var API_URL = "https://api.iaon.ai"
	var API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZieHR2amZmaHNpcm55eGpjdWt1Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcyMjUxNjU2NCwiZXhwIjoyMDM4MDkyNTY0fQ.1IvdUdoQu5yNHllvFQA_tFGDSbydAB5bjFSCxXcZ260"
	for {
		cli, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{
			Schema: "twitter",
		})
		if err != nil {
			slog.Error("supabase.NewClient", "err", err.Error())
			return
		} else {
			client = cli
			break
		}
	}

	accounts, err := GetLoginAccount()

	if err != nil {
		slog.Error(err.Error())
	}

	for k, v := range accounts {
		//v.Timer = time.NewTimer(time.Duration(k) * time.Duration(5) * time.Minute)
		accChan <- ScraperWithTimer{
			Scraper: v,
			Timer:   time.NewTimer(time.Duration(k) * time.Duration(5) * time.Minute),
		}
	}
}

// func TwitterAccountFromDB() ([]TwitterAccount, error) {

// 	data, count, err := client.From("account").Select("*", "exact", false).Eq("available", "true").Execute()

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

// 	slog.Info("TwitterAccountFromDB", "count", count)

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

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

// 	return res, nil
// }

const FollowType = "followers"
const RetweetType = "retweeters"
const TweetLikingUsersType = "tweet_liking_users"

// func ListToQueue(done <-chan interface{}, inStream <-chan TaskIdAndList) <-chan TaskIdAndProfiles {

// 	outStream := make(chan TaskIdAndProfiles, 1)

// 	go func() {

// 		for {
// 			select {
// 			case <-done:
// 				return
// 			case users, ok := <-inStream:
// 				if ok == false {
// 					return
// 				}

// 				c := 0

// 				// if c < 100 {
// 				// 	c = c + 1

// 				res := make([]Profile, 0, users.List.Len())

// 				for e := users.List.Front(); e != nil; e = e.Next() {
// 					if user, ok := e.Value.(Profile); ok {
// 						//fmt.Printf("The data is a string: %s\n", str)
// 						res = append(res, user)

// 						c = c + 1

// 						if c%100 == 0 {
// 							fmt.Println("BackListToQueue", "len(inStream)", len(inStream), "len(outStream)", len(outStream), "len(res)", len(res))

// 							select {
// 							case <-done:
// 								return
// 							case outStream <- TaskIdAndProfiles{
// 								Profiles: res,
// 								TaskId:   users.TaskId,
// 								TaskType: users.TaskType,
// 							}:

// 								res = make([]Profile, 0, users.List.Len())
// 							}

// 						}
// 					}
// 				}

// 				fmt.Println("BackListToQueue", "len(inStream)", len(inStream), "len(outStream)", len(outStream), "len(res)", len(res))

// 				select {
// 				case <-done:
// 					return
// 				case outStream <- TaskIdAndProfiles{
// 					Profiles: res,
// 					TaskId:   users.TaskId,
// 					TaskType: users.TaskType,
// 				}:
// 				}

// 				// } else {
// 				// 	c = 0
// 				// }

// 			}
// 		}
// 	}()

// 	return outStream
// }

// func InsertOrUpdateFinishTask(done <-chan interface{}, inStream <-chan TaskIdAndProfiles) error {

// 	go func() {

// 		for {
// 			select {
// 			case <-done:
// 				return
// 			case users, ok := <-inStream:
// 				if ok == false {
// 					return
// 				}

// 				var res []byte
// 				var err error

// 				//if users.TaskType == FollowType {
// 				rows := make([]Follower, 0, len(users.Profiles))

// 				for _, user := range users.Profiles {

// 					sDec, _ := b64.StdEncoding.DecodeString(user.UserID)
// 					userId, _ := strings.CutPrefix(string(sDec), "User:")

// 					row := Follower{
// 						Follower: userId,
// 						UserName: user.Username,
// 						UserId:   users.TaskId,
// 					}
// 					rows = append(rows, row)
// 				}
// 				res, _, err = client.From(users.TaskType).Insert(rows, true, "", "representation", "").Execute()
// 				//}

// 				if err != nil {
// 					slog.Error("insert into followers or retweeters ", err)

// 					for _, user := range users.Profiles {
// 						usersAsJson, err := json.Marshal(user)
// 						if err != nil {
// 							slog.Error("insert into followers or retweeters json.Marshal", err)
// 							continue
// 						}

// 						sDec, _ := b64.StdEncoding.DecodeString(user.UserID)
// 						userId, _ := strings.CutPrefix(string(sDec), "User:")

// 						slog.Error("insert into followers or retweeters error", string(usersAsJson), userId)
// 					}

// 				} else {
// 					slog.Info("insert into followers or retweeters", string(res), err)
// 				}

// 				fmt.Println("InsertOrUpdateUsers", "len(inStream)", len(inStream))

// 			}
// 		}

// 	}()

// 	return nil

// }

//UserTask

type TaskRes struct {
	UserTask
	Id        int    `json:"id"`
	CreatedAt string `json:"created_at"`
}

type UserTaskIdAndTime struct {
	TaskInDB
	Id        int    `json:"id"`
	CreatedAt string `json:"created_at"`
}

type TaskInDB struct {
	// ID       int    `json:"id"`
	User          string `json:"user_id"`
	TaskType      string `json:"task_type"`
	TaskId        string `json:"task_id"`
	Start         bool   `json:"start"`
	Stop          bool   `json:"stop"`
	FollowerCount int    `json:"follower_count"`
}

func QueryAllTask() ([]TaskInDB, error) {

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

	if err != nil {
		return nil, err
	}

	_ = count

	// fmt.Println(count, string(data))

	res := make([]TaskInDB, 0, count)

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

	return res, nil

}

type TaskJob struct {
	TaskId   string
	Idx      []UserTask
	UserId   string
	TaskType string
	Config
	FollowerCount int
}

func (job *TaskJob) String() string {

	jobAsJson, _ := json.Marshal(job)
	return string(jobAsJson)
}

func GetTasks() ([]TaskJob, error) {

	tasks, err := QueryAllTask()

	if err != nil {
		return nil, err
	}

	res := make([]TaskJob, 0, 10)

	for _, task := range tasks {

		data, count, err := client.From(task.TaskType).Select("", "user_id", false).
			Eq("task_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([]UserTask, 0, 10)

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

		taskJob := TaskJob{
			Idx:           userRes,
			UserId:        task.User,
			TaskType:      task.TaskType,
			TaskId:        task.TaskId,
			FollowerCount: task.FollowerCount,
		}

		// taskJob := NewTaskJob(task.TaskId, task.User, task.TaskType)

		taskJob.Idx = userRes

		res = append(res, taskJob)

	}

	projects, err := QueryAvailableProject()

	if err != nil {
		return nil, err
	}

	resWithKeys := make([]TaskJob, 0, 10)

	for _, v := range projects {

		for _, r := range res {
			if v.UserId == r.UserId {
				r.Config = v.Config
				resWithKeys = append(resWithKeys, r)
			}
		}
	}

	return resWithKeys, nil
}

type UserTask struct {
	//user_id
	TaskId   string `json:"task_id"`
	UserId   string `json:"user_id"`
	UserName string `json:"user_name"`
}

func InsertTaskRes(content []UserTask, tableName string, taskId string) error {

	rows := make([]UserTask, 0, len(content))

	for _, v := range content {
		v.TaskId = taskId
		rows = append(rows, v)
	}

	res, _, err := client.From(tableName).Insert(rows, true, "", "representation", "").Execute()

	if err != nil {
		return err
	}

	_ = res
	return nil
}
