/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package task

import (
	"testing"

	"context"
	"errors"
	"time"
)

type testTask struct {
	done   context.CancelFunc
	test   string
	result bool
	wait   time.Duration
}

func (tt *testTask) Key() string {
	return "test"
}

func (tt *testTask) Err() error {
	if tt.result {
		return nil
	}
	return errors.New(tt.test)
}

func (tt *testTask) Do(ctx context.Context) error {
	if tt.done != nil {
		defer tt.done()
	}
	wait := tt.wait
	if wait == 0 {
		<-time.After(time.Second)
	} else {
		<-time.After(wait)
	}
	return tt.Err()
}

func TestBaseAsyncTasker_AddTask(t *testing.T) {
	at := NewTaskService()
	at.Run()
	<-at.Ready()
	defer at.Stop()

	ctx, cancel := context.WithCancel(context.Background())
	err := at.Add(ctx, nil)
	if err == nil {
		t.Fatalf("add nil task should be error")
	}
	cancel()

	testCtx1, testC1 := context.WithCancel(context.Background())
	err = at.Add(testCtx1, &testTask{
		done: testC1,
		test: "test1",
	})
	if testCtx1.Err() == nil || err == nil || err.Error() != "test1" {
		t.Fatalf("first time add task should be sync")
	}
	lt, _ := at.LatestHandled("test")
	if lt.Err().Error() != "test1" {
		t.Fatalf("should get first handled task 'test1'")
	}

	testCtx2, testC2 := context.WithTimeout(context.Background(), 3*time.Second)
	err = at.Add(testCtx2, &testTask{
		done: testC2,
		test: "test2",
	})
	if err.Error() != "test1" {
		t.Fatalf("second time add task should return prev result")
	}
	<-testCtx2.Done()
	// pkg/task/executor.go:53
	<-time.After(time.Millisecond)
	lt, _ = at.LatestHandled("test")
	if lt.Err().Error() != "test2" {
		t.Fatalf("should get second handled task 'test2'")
	}
}

func TestBaseAsyncTasker_Stop(t *testing.T) {
	at := NewTaskService()
	at.Stop()
	at.Run()

	_, cancel := context.WithCancel(context.Background())
	err := at.Add(context.Background(), &testTask{
		done:   cancel,
		test:   "test stop",
		result: true,
	})
	if err != nil {
		t.Fatalf("add task should be ok")
	}
	_, cancel = context.WithCancel(context.Background())
	err = at.Add(context.Background(), &testTask{
		done:   cancel,
		test:   "test stop",
		wait:   3 * time.Second,
		result: true,
	})
	if err != nil {
		t.Fatalf("add task should be ok")
	}
	<-time.After(time.Second)
	at.Stop()

	err = at.Add(context.Background(), &testTask{result: true})
	if err != nil {
		t.Fatalf("add task should be ok when Tasker is stopped")
	}

	at.Stop()
}
