package executionpool

import (
	"context"
	"go-ethereum-advance/common"
	"go-ethereum-advance/core"
	"go-ethereum-advance/core/state"
	"go-ethereum-advance/core/transcut"
	"go-ethereum-advance/core/types"
	"go-ethereum-advance/core/vm"
	"go-ethereum-advance/params"
	"log"
	"math/big"
	"sync"
	"time"
)

//type Task func(msg types.Message, config *params.ChainConfig, bc core.ChainContext, author *common.Address, gp *core.GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error)
type Task struct {
	item *transcut.Item
	config *params.ChainConfig
	bc core.ChainContext
	author *common.Address
	gp *core.GasPool
	statedb *state.StateDB
	blockNumber *big.Int
	blockHash common.Hash
	usedGas *uint64
	evm *vm.EVM
	level int  //批次
}

func NewTask(config *params.ChainConfig,bc core.ChainContext,author *common.Address,gp *core.GasPool,statedb *state.StateDB,blockNumber *big.Int,blockHash common.Hash,item *transcut.Item,usedGas *uint64,evm *vm.EVM,level int) *Task {
	return &Task{
		item: item,
		config: config,
		bc: bc,
		author: author,
		gp: gp,
		statedb: statedb,
		blockNumber: blockNumber,
		blockHash: blockHash,
		usedGas: usedGas,
		evm: evm,
		level:level,
	}
}

func (t *Task)DoTask() (*types.Receipt, error) {
	return core.ApplyTransactionForExecPool(t.item.MessageInfo(),t.config,t.bc,t.author,t.gp,t.statedb,t.blockNumber,t.blockHash,t.item.TxInfo(),t.usedGas,t.evm,t.level)
}

type Pool struct {
	MaxWorkerIdleTime time.Duration // worker 最大空闲时间
	MaxWorkerNum int32 // 协程最大数量
	TaskEntryChan chan *Task // 任务入列
	Workers []*worker // 已创建worker
	FreeWorkerChan chan *worker // 空闲worker
	Lock sync.Mutex
	ResultChan chan *Result
}

const (
	WorkerStatusStop = 1
	WorkerStatusLive = 0
)

const (
	MaxWaitingTime = 3
)

type worker struct {
	Pool *Pool
	StartTime time.Time // 开始时间
	TaskChan chan *Task // 执行队列
	LastWorkTime time.Time // 最后执行时间
	Ctx context.Context
	Cancel context.CancelFunc
	Status int32 // 被过期删掉的标记
	//ResultChan chan *Result //执行结果
}

type Result struct {
	Receipt *types.Receipt //
	Err error
	Tx    *types.Transaction
}

// 初始化
func NewPool(num int) *Pool {
	p := &Pool{
		MaxWorkerIdleTime: MaxWaitingTime * time.Second,
		MaxWorkerNum:      int32(num),
		TaskEntryChan:     make(chan *Task, 2000),
		FreeWorkerChan:    make(chan *worker, 2000),
		ResultChan:        make(chan *Result, num),
	}
	// 分发任务
	go p.dispatchTask()
	//清理空闲worker
	go p.fireWorker()
	return p
}
// 定期清理空闲worker
func (p *Pool) fireWorker() {
	for {
		select {
		case <-time.After(MaxWaitingTime * time.Second):
			for k, w := range p.Workers {
				if time.Now().Sub(w.LastWorkTime) > p.MaxWorkerIdleTime {
					log.Printf("overtime %v %p", k, w)
					// 终止协程
					w.Cancel()
					// 清理Free
					w.Status = WorkerStatusStop
				}
			}
			p.Lock.Lock()
			p.Workers = p.cleanWorker(p.Workers)
			p.Lock.Unlock()
		}
	}
}
// 递归清理无用worker
func (p *Pool) cleanWorker(workers []*worker) []*worker {
	for k, w := range workers {
		if time.Now().Sub(w.LastWorkTime) > p.MaxWorkerIdleTime {
			workers = append(workers[:k], workers[k+1:]...) // 删除中间1个元素
			return p.cleanWorker(workers)
		}
	}
	return workers
}
// 分发任务
func (p *Pool) dispatchTask() {
	for {
		select {
		case t := <-p.TaskEntryChan:
			log.Printf("dispatch task %p", t)
			// 获取worker
			w := p.fetchWorker()
			// 将任务扔给worker
			w.accept(t)
		}
	}
}
// 获取可用worker
func (p *Pool) fetchWorker() *worker {
	for {
		select {
		// 获取空闲worker
		case w := <-p.FreeWorkerChan:
			if w.Status == WorkerStatusLive {
				return w
			}
		default:
			// 创建新的worker
			if int32(len(p.Workers)) < p.MaxWorkerNum {
				w := &worker{
					Pool:         p,
					StartTime:    time.Now(),
					LastWorkTime: time.Now(),
					TaskChan:     make(chan *Task, 1),
					Ctx:          context.Background(),
					Status:       WorkerStatusLive,
				}
				ctx, cancel := context.WithCancel(w.Ctx)
				w.Cancel = cancel
				// 接到任务自己去执行
				go w.execute(ctx)
				p.Lock.Lock()
				p.Workers = append(p.Workers, w)
				p.Lock.Unlock()
				p.FreeWorkerChan <- w
				log.Printf("worker create %p", w)
			}
		}
	}
}
// 添加任务
func (p *Pool) addTask(t Task) {
	// 将任务放到入口任务队列
	p.TaskEntryChan <- &t
}
// 接受任务
func (w *worker) accept(t *Task) {
	// 每个worker自己的工作队列
	w.TaskChan <- t
}
// 执行任务
func (w *worker) execute(ctx context.Context) {
	for {
		select {
		case t := <-w.TaskChan:
			// 执行
			result,err := t.DoTask()
			// 记录工作状态
			w.Pool.ResultChan <- &Result{Receipt: result,Err: err,Tx:t.item.TxInfo()}
			w.LastWorkTime = time.Now()
			w.Pool.FreeWorkerChan <- w
		case <-ctx.Done():
			log.Printf("worker done %p", w)
			return
		}
	}
}
// 执行
func (p *Pool)AddTask(t Task) {
	p.addTask(t)
}