// package dict_warbot -- потокобезопасный словарь ботов
package dict_warbot

import (
	"fmt"
	"strconv"
	"strings"
	"sync"
	"wartank/pkg/alias"
	"wartank/pkg/components/kernel/logger"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot"
)

const (
	strBotList = "/bots/list" // Константа путь к списку ботов в базе
)

// СловарьБотов -- потокобезопасный словарь ботов
type СловарьБотов struct {
	сервер  types.ИСервер
	хран    types.ИХранилище
	словарь map[alias.БотНомер]types.ИБот
	блок    sync.RWMutex
	лог     types.ИЛоггер
}

// НовСловарьБотов -- возвращает новый потокобезопасный словарь ботов
func НовСловарьБотов(сервер types.ИСервер) *СловарьБотов {
	лог := logger.НовЛоггер("СловарьБотов")
	лог.Инфо("НовСловарьБотов()\n")
	лог.Паника(сервер == nil, "НовСловарьБотов(): ИСервер==nil")
	сам := &СловарьБотов{
		сервер:  сервер,
		хран:    сервер.Хранилище(),
		словарь: map[alias.БотНомер]types.ИБот{},
		лог:     лог,
	}
	сам.load()
	return сам
}

// ListBot -- возвращает список существующих ботов
func (сам *СловарьБотов) ListBot() []types.ИБот {
	сам.блок.RLock()
	defer сам.блок.RUnlock()
	lst := make([]types.ИБот, 0)
	for _, bot := range сам.словарь {
		lst = append(lst, bot)
	}
	return lst
}

// Get -- возвращает бота по имени
func (сам *СловарьБотов) Get(botNumber alias.БотНомер) types.ИБот {
	сам.блок.RLock()
	defer сам.блок.RUnlock()
	bot := сам.словарь[botNumber]
	return bot
}

// Add -- добавляет нового бота в словарь
func (сам *СловарьБотов) Add(bot types.ИБот) {
	сам.блок.Lock()
	defer сам.блок.Unlock()
	if bot == nil {
		return
	}
	сам.словарь[bot.Номер()] = bot
	сам.save()
}

// Сохраняет словарь ботов в базе
func (сам *СловарьБотов) save() {
	strNumber := ""
	for botNumber := range сам.словарь {
		strNumber += fmt.Sprint(botNumber) + ";"
	}
	strNumber = strNumber[:len(strNumber)-1]
	err := сам.хран.Уст(strBotList, []byte(strNumber))
	if err != nil {
		сам.сервер.Отменить()
	}
}

// Загружает всех ботов с базы
func (сам *СловарьБотов) load() {
	binNumber, err := сам.хран.Получ(strBotList)
	if err != nil {
		if !strings.Contains(err.Error(), "not found") {
			сам.лог.Паника(true, "СловарьБотов.load(): при загрузке списка ботов, ош=\n\t%n\t", err)
		}
	}
	strNumbers := string(binNumber)
	if strNumbers == "" {
		return
	}
	lstNumbers := strings.Split(strNumbers, ";")
	for _, strNumber := range lstNumbers {
		if strNumber == "" {
			continue
		}
		iNumber, err := strconv.Atoi(strNumber)
		сам.лог.Паника(err != nil, "СловарьБотов.load(): при получении номера бота, ош=\n\t%v\n", err)
		number := alias.БотНомер(iNumber)
		_, isOk := сам.словарь[number]
		if isOk {
			continue
		}
		bot, err := warbot.ЗагрузитьВарБот(сам.сервер, number)
		сам.лог.Паника(err != nil, "СловарьБотов.load(): при загрузке бота, ош=\n\t%v\n", err)
		if bot.АвтоИграЕсли() {
			go bot.Пуск()
		}
		сам.словарь[number] = bot
	}
}
