package imitater

import (
	"fmt"
	"log"
	"reflect"
	"time"

	"474420502.top/eson/crontabex"

	"474420502.top/eson/structure/circular_linked"

	"474420502.top/eson/curl2info"
)

// ITask 继承这个接口的类
type ITask interface {
	Execute(data map[string]interface{}) ITask
	Init()

	SetCrontab(cron string)
	GetCrontab() *crontab.Crontab

	SetName(name string)
	GetName() string

	SetCurl(Curl *curl2info.CURL)
	GetCurl() *curl2info.CURL

	GetProxies() *clinked.CircularLinked
	AddProxies(proxy string)

	SetADInfo(adinfo ADInfo)
	GetADInfo() *ADInfo

	TimeUp() bool
	NextTime() time.Time
}

var register = make(map[string]reflect.Type)

func init() {
	log.SetFlags(log.Llongfile)
}

// Register 注册 类型 ITask为样本的类型
func Register(name string, itask ITask) {
	register[name] = reflect.TypeOf(itask).Elem()
}

func makeRegisterType(name string) ITask {
	result := reflect.New(register[name]).Interface().(ITask)
	result.SetName(name)
	return result
}

// Person 以人为单位
type Person struct {
	Tasks []ITask
	Conf  *Config
}

// NewPerson 创建一个人实例
func NewPerson() *Person {
	person := &Person{}

	// person.Conf = NewConfig(conf)
	// person.Tasks = SplitTasks(person.Conf)

	return person
}

// Config 加载配置
func (person *Person) Config(conf string) {
	person.Conf = NewConfig(conf)
	person.Tasks = splitTasks(person.Conf)
}

// NewPersonWithConfig 创建一个person
func NewPersonWithConfig(conf string) *Person {
	person := NewPerson()
	person.Config(conf)
	return person
}

// SplitTasks 拆开出需求的任务
func splitTasks(conf *Config) []ITask {
	var tasks []ITask
	proxies := (*clinked.CircularLinked)(conf.Proxies)
	for _, scurl := range conf.Curls {
		curl := curl2info.ParseRawCURL(scurl)

		if curl.ITask == "" {
			curl.ITask = conf.ITask
		}
		task := makeRegisterType(curl.ITask)
		switch conf.Mode {
		case 0:
			initTask(conf, task, curl)
			// 初始化代理
			if proxies != nil {
				for _, cnode := range proxies.GetLoopValues() {
					proxy := cnode.GetValue().(string)
					task.AddProxies(proxy)
				}
			}

			tasks = append(tasks, task)
		case 1:
			if proxies != nil {
				for _, cnode := range proxies.GetLoopValues() {
					proxy := cnode.GetValue().(string)

					ncurl := curl2info.ParseRawCURL(scurl)

					if curl.ITask == "" {
						curl.ITask = conf.ITask
					}
					ptask := makeRegisterType(ncurl.ITask).(ITask)
					initTask(conf, ptask, ncurl)

					ptask.AddProxies(proxy)
					tasks = append(tasks, ptask)
				}
			}
		}
	}
	return tasks
}

// Execute 人的执行所有任务
func (person *Person) Execute() {

	taskLen := len(person.Tasks)

	result := make(chan string, 1)
	for _, task := range person.Tasks {

		go ExecuteOnPlan(task, result)

	}

	for t := range result {
		log.Println(t)
		taskLen--
		if taskLen <= 0 {
			close(result)
		}
	}

	// engine := gin.Default()
	// engine.Run()
}

// initTask 生成一个新任务
func initTask(conf *Config, task ITask, curl *curl2info.CURL) {

	if curl.Crontab != "" {
		task.SetCrontab(curl.Crontab)
	} else {
		task.SetCrontab(conf.Crontab)
	}

	task.SetADInfo(conf.ADInfo)
	task.SetCurl(curl)

	task.Init()
}

// ExecuteOnPlan 按照计划执行任务并返回结果
func ExecuteOnPlan(task ITask, result chan string) {
	data := make(map[string]interface{})
	var rtask ITask
	taskname := task.GetName()
	urlname := task.GetCurl().Name

	task.NextTime() // 必须调用NextTime 才能触发TimeUp
	for {
		interval := time.Second * 2
		if task.TimeUp() {
			rtask = task.Execute(data) // 事件 在这里变化
			ntime := task.NextTime()
			interval = ntime.Sub(time.Now())
			if rtask == nil {
				// log.Println("rtask is nil")
				result <- fmt.Sprintf("rtask is nil, the first task = %s, name = %s", taskname, urlname)
				return
			}
			task = rtask
		}
		time.Sleep(interval)
	}
}
