// package arena -- типовая арена работы части игры (банк, арсенал и т.п.)
package arena

import (
	"fmt"
	"log"
	"sync"
	"wartank/pkg/alias"
	"wartank/pkg/arena/arena_context"
	"wartank/pkg/arena/arena_string"
	"wartank/pkg/arena/down_time"
	"wartank/pkg/types"
)

// АренаКонфиг -- конфигурация арены
type АренаКонфиг struct {
	Бот_         types.ИБот
	АренаИмя_    alias.АренаИмя
	СтрКонтроль_ string // Контрольная строка для арены
	СтрУрл_      string // Адрес арены
	ФнПуск_      func()
}

// Контролирует правильность параметров
func (конф *АренаКонфиг) контроль() {
	if конф.СтрКонтроль_ == "" {
		panic("АренаКонфиг.СтрКонтроль_ == \"\"")
	}
	if конф.ФнПуск_ == nil {
		panic("АренаКонфиг.ФнПуск_ == nil")
	}
	if конф.Бот_ == nil {
		panic("АренаКонфиг.Бот_ == nil")
	}
	if конф.АренаИмя_ == "" {
		panic("АренаКонфиг.СценаИмя_ == \"\"")
	}
	if конф.СтрУрл_ == "" {
		panic("АренаКонфиг.СтрУрл_ == \"\"")
	}
}

// Арена -- арена игры
type Арена struct {
	types.ИАренаКонтекст
	времяОстат types.ИВремяОстат         // Обратный отсчёт до окончания работы режима
	списСтр    *arena_string.АренаСтроки // Список строк из сети для анализа секции
	конф       АренаКонфиг
	блок       sync.RWMutex
}

// НовАрена -- возвращает новую арену игры
func НовАрена(конф АренаКонфиг) *Арена {
	log.Printf("НовАрена(): стрКонтроль=%q\n", конф.СтрКонтроль_)
	конф.контроль()
	аренаКонтекст := arena_context.НовАренаКонтекст(конф.Бот_, конф.АренаИмя_)
	сам := &Арена{
		ИАренаКонтекст: аренаКонтекст,
		времяОстат:     down_time.НовВремОбрат(аренаКонтекст, 5),
		списСтр:        arena_string.НовАренаСтроки(конф.СтрКонтроль_),
		конф:           конф,
	}
	_ = types.ИАрена(сам)
	return сам
}

// Пуск -- запускает арену
func (сам *Арена) Пуск() {
	сам.Обновить()
	сам.конф.ФнПуск_()
}

// Обновить -- обновляет арену
func (сам *Арена) Обновить() {
	списСтр := сам.СписПолучить()
	if len(списСтр) == 0 {
		списСтр = сам.Бот().Сеть().ВебВоркер().Получ(сам.конф.СтрУрл_)
	}
	ош := сам.СтрОбновить(списСтр)
	if ош != nil {
		log.Printf("Арена.Обновить(): ош=\n\t%v\n", ош)
		сам.Отмена()
	}
}

// СтрОбновить -- обновляет список строк секции по требованию
func (сам *Арена) СтрОбновить(lstString []string) error {
	if err := сам.списСтр.Set(lstString); err != nil {
		return fmt.Errorf("Арена.СтрОбновить(): при установке lstString, err=\n\t%w", err)
	}
	return nil
}

// СписПолучить -- возвращает список строк секции
func (сам *Арена) СписПолучить() []string {
	return сам.списСтр.Получ()
}

// ОбратВремяУст -- устанавливает новое значение обратного счётчика времени
func (сам *Арена) ОбратВремяУст(времяСек alias.Время) error {
	ош := сам.времяОстат.Уст(времяСек)
	if ош != nil {
		return fmt.Errorf("Арена.ОбратВремяУст(): ош=\n\t%w", ош)
	}
	return nil
}

// ВремяОстат -- объект оставшегося времени
func (сам *Арена) ВремяОстат() types.ИВремяОстат {
	сам.блок.RLock()
	defer сам.блок.RUnlock()
	return сам.времяОстат
}
