package down_time

import (
	"testing"
	"time"
	"wartank/pkg/alias"
	"wartank/pkg/components/safe_bool"

	// "wartank/pkg/mock/mock_zone"
	"wartank/pkg/mock/mockapp"
	"wartank/pkg/types"
)

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

// Тестер для счётчика времени
type tester struct {
	t      *testing.T
	app    *mockapp.MockApp
	zone   types.ИАренаКонтекст
	ct     *ВремОбрат
	err    error
	isCall *safe_bool.БезопБул // Признак обратного вызова
}

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

func TestCountTime(t *testing.T) {
	test := &tester{
		t:      t,
		isCall: safe_bool.НовБезопБул(),
		app:    mockapp.NewMockApp(),
	}
	time.Sleep(time.Millisecond * 100)
	test.create()
	test.setInt()
	test.setStr()
	test.checkTick()
	test.cancel()
}

// Оменяет работу таймера
func (сам *tester) cancel() {
	сам.t.Logf("=cancel=\n")
	_ = НовВремОбрат(сам.zone, 0)
	сам.app.CancelApp()
	time.Sleep(time.Millisecond * 150)
}

// Проверяет обработчик тика
func (сам *tester) checkTick() {
	времОбрат := НовВремОбрат(сам.zone, 0)
	{ // Секундный тик
		ош := времОбрат.Уст("00:00:08")
		if ош != nil {
			сам.t.Errorf("checkTick(): ош=%v", ош)
		}
		time.Sleep(time.Second * 1)
		if val := времОбрат.String(); val != "00:00:08" {
			сам.t.Errorf("checkTick(): счётчик(%v)!='00:00:08'", val)
		}
	}
	{ // Проверка времени прямо сейчас
		time.Sleep(time.Millisecond * 100)
		if val := времОбрат.String(); val != "00:00:08" {
			сам.t.Errorf("checkTick(): счётчик(%v)!='00:00:08'", val)
		}
	}
	{ // Проверка обратного вызова прямо сейчас
		strTime := alias.Время(time.Now().UTC().Format("15:04:05"))
		ош := времОбрат.Уст(strTime)
		if ош != nil {
			сам.t.Errorf("checkTick(): ош=%v", ош)
		}
		if val := времОбрат.String(); val != string(strTime) {
			сам.t.Errorf("checkTick(): счётчик(%v)!=%s", val, strTime)
		}
		// Выход из функции -- и есть факт обратного вызова
		сам.call()
		{ // Проверка отсутствия обратного вызова прямо сейчас
			ош := времОбрат.Уст("00:00:00")
			if ош != nil {
				сам.t.Errorf("checkTick(): ош=%v", ош)
			}
			// Выход из функции -- и есть факт обратного вызова
			сам.call()
			if val := времОбрат.ПолучМилСек(); val != 0 {
				сам.t.Errorf("checkTick(): счётчик(%v)!=0", val)
			}
			времОбрат.Стоп()
			сам.app.CancelApp()
			time.Sleep(time.Millisecond * 50)
		}
	}
}

func (сам *tester) setStrBad1(strBad alias.Время) {
	defer func() {
		if _panic := recover(); _panic == nil {
			сам.t.Errorf("setStrBad1(): panic==nil\n")
		}
	}()
	if сам.err = сам.ct.Уст(strBad); сам.err == nil {
		сам.t.Errorf("setStrBad1(): BAD-2 err==nil")
	}
}

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

// Устанавливает число секунд для отсчёта
func (сам *tester) setInt() {
	go сам.call()
	// сам.zone = mock_zone.НовМокСцена()
	ct := НовВремОбрат(сам.zone, 0)
	{ // GOOD-1
		if сам.err = ct.Уст("8"); сам.err != nil {
			сам.t.Errorf("setInt(): GOOD-1 err=%v", сам.err)
		}
		if ct.остатПарсер.Час().Получ() != 0 {
			сам.t.Errorf("setInt(): GOOD-1 hour(%v)!=0", сам.ct.остатПарсер.Час().Получ())
		}
		if ct.остатПарсер.Мин().Получ() != 0 {
			сам.t.Errorf("setInt(): GOOD-1 min(%v)!=0", сам.ct.остатПарсер.Мин().Получ())
		}
		if ct.остатПарсер.Сек().Получ() != 8 {
			сам.t.Errorf("setInt(): GOOD-1 sec(%v)!=8", сам.ct.остатПарсер.Сек().Получ())
		}
		if strVal := ct.String(); strVal != "00:00:08" {
			сам.t.Errorf("setInt(): GOOD-1 strVal(%v)!='00:00:08'", strVal)
		}
	}
	{ // GOOD-2
		if сам.err = ct.Уст("121"); сам.err != nil {
			сам.t.Errorf("setInt(): GOOD-2 err=%v", сам.err)
		}
		if ct.остатПарсер.Час().Получ() != 0 {
			сам.t.Errorf("setInt(): GOOD-2 hour(%v)!=0", сам.ct.остатПарсер.Час().Получ())
		}
		if ct.остатПарсер.Мин().Получ() != 2 {
			сам.t.Errorf("setInt(): GOOD-2 min(%v)!=2", сам.ct.остатПарсер.Мин().Получ())
		}
		if ct.остатПарсер.Сек().Получ() != 1 {
			сам.t.Errorf("setInt(): GOOD-2 sec(%v)!=1", сам.ct.остатПарсер.Сек().Получ())
		}
		if strVal := ct.String(); strVal != "00:02:01" {
			сам.t.Errorf("setInt(): GOOD-2 strVal(%v)!='00:02:01'", strVal)
		}
	}
	{ // GOOD-3
		if сам.err = ct.Уст("7203"); сам.err != nil {
			сам.t.Errorf("setInt(): GOOD-3 err=%v", сам.err)
		}
		if ct.остатПарсер.Час().Получ() != 2 {
			сам.t.Errorf("setInt(): GOOD-3 hour(%v)!=2", сам.ct.остатПарсер.Час().Получ())
		}
		if ct.остатПарсер.Мин().Получ() != 0 {
			сам.t.Errorf("setInt(): GOOD-3 min(%v)!=0", сам.ct.остатПарсер.Мин().Получ())
		}
		if ct.остатПарсер.Сек().Получ() != 3 {
			сам.t.Errorf("setInt(): GOOD-3 sec(%v)!=3", сам.ct.остатПарсер.Сек().Получ())
		}
		if strVal := ct.String(); strVal != "02:00:03" {
			сам.t.Errorf("setInt(): GOOD-3 strVal(%v)!='02:00:03'", strVal)
		}
	}
}

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

// Правильное создание
func (сам *tester) createGood1() {
	defer func() {
		if _panic := recover(); _panic != nil {
			сам.t.Errorf("createGood1(): panic=\n\t%v", _panic)
		}
	}()
	// сам.zone = mock_zone.НовМокСцена()
	ct := НовВремОбрат(сам.zone, 1)
	if ct == nil {
		сам.t.Errorf("createGood1(): countTime==nil")
	}
	if val := ct.ПолучМилСек(); val != 0 {
		сам.t.Errorf("createGood1(): val(%v)!=0", val)
	}
}

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