package counttime

import (
	"testing"
	"time"
	"wartank/pkg/components/safebool"
	"wartank/pkg/mock/mockapp"
)

/*
	Тест для счётчика времени
*/

// Тестер для счётчика времени
type tester struct {
	t      *testing.T
	app    *mockapp.MockApp
	ct     *CountTime
	err    error
	isCall *safebool.SafeBool // Признак обратного вызова
}

// Обратный вызов для счётчика времени
func (sf *tester) call() {
	<-sf.ct.chCall
}

func TestCountTime(t *testing.T) {
	test := &tester{
		t:      t,
		isCall: safebool.NewSafeBool(),
		app:    mockapp.NewMockApp(),
	}
	time.Sleep(time.Millisecond * 100)
	test.create()
	test.setInt()
	test.setStr()
	test.checkTick()
	test.cancel()
}

// Оменяет работу таймера
func (sf *tester) cancel() {
	sf.t.Logf("=cancel=\n")
	ct := NewCountTime(sf.app)
	for len(ct.chTick) > 0 {
		<-ct.chTick
	}
	sf.app.CancelApp()
	time.Sleep(time.Millisecond * 150)
}

// Проверяет обработчик тика
func (sf *tester) checkTick() {
	ct := NewCountTime(sf.app)
	{ // Секундный тик
		ct.Parse("00:00:08")
		time.Sleep(time.Second * 1)
		ct.chTick <- 1
		time.Sleep(time.Millisecond * 20)
		if val := ct.String(); val != "00:00:08" {
			sf.t.Errorf("checkTick(): счётчик(%v)!='00:00:08'", val)
		}
	}
	{ // Проверка времени прямо сейчас
		ct.chTick <- 1
		time.Sleep(time.Millisecond * 20)
		if val := ct.String(); val != "00:00:08" {
			sf.t.Errorf("checkTick(): счётчик(%v)!='00:00:08'", val)
		}
	}
	{ // Проверка обратного вызова прямо сейчас
		strTime := time.Now().UTC().Format("15:04:05")
		ct.Parse(strTime)
		if val := ct.String(); val != strTime {
			sf.t.Errorf("checkTick(): счётчик(%v)!=%s", val, strTime)
		}
		ct.chTick <- 1
		// Выход из функции -- и есть факт обратного вызова
		sf.call()
		{ // Проверка отсутствия обратного вызова прямо сейчас
			ct.Parse("00:00:00")
			ct.chTick <- 1
			// Выход из функции -- и есть факт обратного вызова
			sf.call()
			if val := ct.Get(); val != 0 {
				sf.t.Errorf("checkTick(): счётчик(%v)!=0", val)
			}
			ct.Stop()
			sf.app.CancelApp()
			time.Sleep(time.Millisecond * 50)
		}
	}
}

func (sf *tester) setStrBad1(strBad string) {
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Errorf("setStrBad1(): panic==nil\n")
		}
	}()
	if sf.err = sf.ct.Parse(strBad); sf.err == nil {
		sf.t.Errorf("setStrBad1(): BAD-2 err==nil")
	}
}

// Устанавливает строковое значение времени
func (sf *tester) setStr() {
	go sf.call()
	ct := NewCountTime(sf.app)
	{ // BAD-1 пустая строка
		if sf.err = ct.Parse(""); sf.err == nil {
			sf.t.Errorf("setStr(): BAD-1 err==nil")
		}
	}
	// BAD-2 неформатная строка
	sf.setStrBad1(":::")
	// BAD-3 кривые часы
	sf.setStrBad1("a1:02:03")
	// BAD-4 кривые минуты
	sf.setStrBad1("01:a2:03")
	// BAD-5 кривые секунды
	sf.setStrBad1("01:02:a3")
	// BAD-6 кривые только секунды
	sf.setStrBad1("a3")
	// BAD-7 кривые минуты +секунды
	sf.setStrBad1("a2:03")
	// BAD-8 кривые часы +минуты +секунды
	sf.setStrBad1("a1:02:03")
	// BAD-9 минуты +кривые секунды
	sf.setStrBad1("02:a3")
	// BAD-10 кривые минуты +секунды
	sf.setStrBad1("60:03")
	// BAD-11 кривые минуты +секунды
	sf.setStrBad1("-1:03")
	// BAD-12 минуты +кривые секунды
	sf.setStrBad1("01:60")
	// BAD-13 минуты +кривые секунды
	sf.setStrBad1("01:-1")
	// BAD-14 кривые часы +минуты + секунды
	sf.setStrBad1("-1:02:03")
	// BAD-15 кривые часы +минуты + секунды
	//sf.setStrBad1("24:02:03")
	{ // GOOD-1 секунды
		if sf.err = ct.Parse("03"); sf.err != nil {
			sf.t.Errorf("setStr(): GOOD-1 err=%v", sf.err)
		}
	}
	{ // GOOD-2 минуты секунды
		if sf.err = ct.Parse("02:03"); sf.err != nil {
			sf.t.Errorf("setStr(): GOOD-2 err=%v", sf.err)
		}
	}
	{ // GOOD-3 часы минуты секунды
		if sf.err = ct.Parse("01:02:03"); sf.err != nil {
			sf.t.Errorf("setStr(): GOOD-3 err=%v", sf.err)
		}
	}
}

// Устанавливает число секунд для отсчёта
func (sf *tester) setInt() {
	go sf.call()
	ct := NewCountTime(sf.app)
	{ // Bad-1 Отрицательное число
		if sf.err = ct.Set(-1); sf.err == nil {
			sf.t.Errorf("setInt(): BAD-1 err==nil")
		}
	}
	{ // GOOD-1
		if sf.err = ct.Set(8); sf.err != nil {
			sf.t.Errorf("setInt(): GOOD-1 err=%v", sf.err)
		}
		if ct.parser.Hour().Get() != 0 {
			sf.t.Errorf("setInt(): GOOD-1 hour(%v)!=0", sf.ct.parser.Hour().Get())
		}
		if ct.parser.Min().Get() != 0 {
			sf.t.Errorf("setInt(): GOOD-1 min(%v)!=0", sf.ct.parser.Min().Get())
		}
		if ct.parser.Sec().Get() != 8 {
			sf.t.Errorf("setInt(): GOOD-1 sec(%v)!=8", sf.ct.parser.Sec().Get())
		}
		if strVal := ct.String(); strVal != "00:00:08" {
			sf.t.Errorf("setInt(): GOOD-1 strVal(%v)!='00:00:08'", strVal)
		}
	}
	{ // GOOD-2
		if sf.err = ct.Set(121); sf.err != nil {
			sf.t.Errorf("setInt(): GOOD-2 err=%v", sf.err)
		}
		if ct.parser.Hour().Get() != 0 {
			sf.t.Errorf("setInt(): GOOD-2 hour(%v)!=0", sf.ct.parser.Hour().Get())
		}
		if ct.parser.Min().Get() != 2 {
			sf.t.Errorf("setInt(): GOOD-2 min(%v)!=2", sf.ct.parser.Min().Get())
		}
		if ct.parser.Sec().Get() != 1 {
			sf.t.Errorf("setInt(): GOOD-2 sec(%v)!=1", sf.ct.parser.Sec().Get())
		}
		if strVal := ct.String(); strVal != "00:02:01" {
			sf.t.Errorf("setInt(): GOOD-2 strVal(%v)!='00:02:01'", strVal)
		}
	}
	{ // GOOD-3
		if sf.err = ct.Set(7203); sf.err != nil {
			sf.t.Errorf("setInt(): GOOD-3 err=%v", sf.err)
		}
		if ct.parser.Hour().Get() != 2 {
			sf.t.Errorf("setInt(): GOOD-3 hour(%v)!=2", sf.ct.parser.Hour().Get())
		}
		if ct.parser.Min().Get() != 0 {
			sf.t.Errorf("setInt(): GOOD-3 min(%v)!=0", sf.ct.parser.Min().Get())
		}
		if ct.parser.Sec().Get() != 3 {
			sf.t.Errorf("setInt(): GOOD-3 sec(%v)!=3", sf.ct.parser.Sec().Get())
		}
		if strVal := ct.String(); strVal != "02:00:03" {
			sf.t.Errorf("setInt(): GOOD-3 strVal(%v)!='02:00:03'", strVal)
		}
	}
}

// Нет обратного канала
func (sf *tester) createBad1() {
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Errorf("createBad1(): panic==nil")
		}
	}()
	sf.ct = NewCountTime(nil)
	if sf.ct != nil {
		sf.t.Errorf("createBad1(): countTime!=nil")
	}
}

// Правильное создание
func (sf *tester) createGood1() {
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Errorf("createGood1(): panic=%v", _panic)
		}
	}()
	ct := NewCountTime(sf.app)
	if ct == nil {
		sf.t.Errorf("createGood1(): countTime==nil")
	}
	if val := ct.Get(); val != 0 {
		sf.t.Errorf("createGood1(): val(%v)!=0", val)
	}
}

// Создание счётчика обратного времени
func (sf *tester) create() {
	sf.createBad1()
	sf.createGood1()
}
