package threadpool

import (
	"fmt"
	"testing"
	"time"
)

const (
	NumberOfWorkers = 20
	QueueSize       = int64(1000)
)

var (
	threadpool *ThreadPool
)

func TestNewThreadPool(t *testing.T) {
	threadpool = NewThreadPool(NumberOfWorkers)
}

func TestThreadPool_Execute(t *testing.T) {
	threadpool = NewThreadPool(NumberOfWorkers)
	data := &TestData{Val: "pristine"}
	task := &TestTask{TestData: data}
	threadpool.Execute(task)

	time.Sleep(2 * time.Second)
	fmt.Println("")

	if data.Val != "changed" {
		t.Fail()
	}
}

func TestThreadPool_ExecuteFuture(t *testing.T) {
	threadpool = NewThreadPool(NumberOfWorkers)

	task := &TestTaskFuture{}
	handle, _ := threadpool.ExecuteFuture(task)
	response := handle.Get()
	if !handle.IsDone() {
		t.Fail()
	}
	fmt.Println("Thread done ", response)
}

func TestThreadPool_Close(t *testing.T) {
	threadpool = NewThreadPool(NumberOfWorkers)

	threadpool.Close()
}

func TestQueueFullError(t *testing.T) {
	threadpool = NewThreadPool(30)
	before := time.Now()

	data := &TestData{Val: "pristine"}
	task := &TestTask{TestData: data}
	for i := 0; i < 30; i++ {
		err := threadpool.Execute(task)
		if err != nil {
			t.Fail()
		}
	}
	threadpool.Close()
	after := time.Now()
	t.Logf("time start %d", after.Sub(before))
	t.Log("success")
}

// func TestQueueFullError_Future(t *testing.T) {
// 	threadpool = NewThreadPool(NumberOfWorkers)

// 	threadpool := NewThreadPool(1)

// 	task := &TestLongTaskFuture{}

// 	_, err := threadpool.ExecuteFuture(task)
// 	if err != nil {
// 		t.Fail()
// 	}

// 	_, err = threadpool.ExecuteFuture(task)

// 	threadpool.Close()
// }

type TestTask struct {
	TestData *TestData
}

type TestData struct {
	Val string
}

func (t *TestTask) Run() {
	time.Sleep(1 * time.Second)
	t.TestData.Val = "changed"
}

type TestLongTask struct{}

func (t TestLongTask) Run() {
	time.Sleep(5 * time.Second)
}

type TestTaskFuture struct{}

func (t *TestTaskFuture) Call() interface{} {
	return "Done"
}

type TestLongTaskFuture struct{}

func (t *TestLongTaskFuture) Call() interface{} {
	time.Sleep(5 * time.Second)
	return "Done"
}
