package angar

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"
	"wartank/pkg/alias"
	"wartank/pkg/arena"
	"wartank/pkg/components/arena_net"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/base"
	"wartank/server/serv_bots/warbot/angar/battle"
	"wartank/server/serv_bots/warbot/angar/convoy"
	"wartank/server/serv_bots/warbot/angar/fuel_attack"
	"wartank/server/serv_bots/warbot/angar/masters"
	"wartank/server/serv_bots/warbot/angar/missions"
	"wartank/server/serv_bots/warbot/angar/netstat"
	"wartank/server/serv_bots/warbot/angar/tank_params"
	"wartank/server/serv_bots/warbot/stat_resurs"
	"wartank/server/serv_bots/warbot/stat_tank/static_param"
)

/*
	Объект ангара приложения
*/

// Ангар -- ангар для танка
type Ангар struct {
	types.ИАрена
	слог types.ИЛоггер
	сеть types.ИАренаСеть
	бот  types.ИБот

	уровень  types.ИСтатПарам
	progress types.ИСтатПарам
	// топливо       *fuel.Топливо
	игроковОнлайн types.ИСтатПарам

	silverOnline types.ИСтатПарам

	сетьТанкСтат *netstat.NetStat
	танкПарам    *tank_params.ТанкПараметры
	словАрена    map[alias.АренаИмя]types.ИАрена
	ресурсы      *stat_resurs.СтатРесурсы
}

// НовАнгар -- возвращает новый *Angar
func НовАнгар(бот types.ИБот) (*Ангар, error) {
	танкПарам, ош := tank_params.НовТанкПараметры(бот)
	if ош != nil {
		return nil, fmt.Errorf("НовАнгар(): при создании параметров танка, ош=\n\t%w", ош)
	}

	сам := &Ангар{
		слог:          бот.Сервер().Слог(),
		бот:           бот,
		уровень:       static_param.НовСтатПарам("level"),
		progress:      static_param.НовСтатПарам("progress"),
		игроковОнлайн: static_param.НовСтатПарам("online"),
		silverOnline:  static_param.НовСтатПарам("silver_online"),
		танкПарам:     танкПарам,
		словАрена:     make(map[alias.АренаИмя]types.ИАрена),
	}
	аренаКонф := arena.АренаКонфиг{
		Бот_:         бот,
		АренаИмя_:    "Ангар",
		СтрКонтроль_: "<title>Ангар</title>",
		ФнПуск_:      сам.пуск,
		СтрУрл_:      "https://wartank.ru/angar",
	}
	сам.ИАрена = arena.НовАрена(аренаКонф)
	сам.сеть = arena_net.НовАренаСеть(сам, "https://wartank.ru/angar")
	var err error
	топливоБой, err := fuel_attack.НовТопливоБой(сам)
	if err != nil {
		return nil, fmt.Errorf("НовАнгар(): in create <AngarAttackNet>, err=\n\t%w", err)
	}
	сам.словАрена["топливоБой"] = топливоБой
	{ // Статистика
		сам.сетьТанкСтат, err = netstat.NewNetStat(сам.бот)
		if err != nil {
			return nil, fmt.Errorf("НовАнгар(): in create NetResource, err=\n\t%w", err)
		}
	}
	конвой := convoy.НовКонвой(сам.бот)
	сам.словАрена["конвой"] = конвой
	сражение := battle.НовСражение(сам.бот)
	сам.словАрена["сражение"] = сражение
	битваМастеров := masters.НовБитваМастеров(сам.бот)
	сам.словАрена["битваМастеров"] = битваМастеров
	база, err := base.НовБаза(сам)
	if err != nil {
		return nil, fmt.Errorf("НовАнгар(): in make IBase, err=\n\t%w", err)
	}
	сам.словАрена["база"] = база
	миссии, err := missions.НовМиссии(сам.бот)
	if err != nil {
		return nil, fmt.Errorf("НовАнгар(): in make *Missions, err=\n\t%w", err)
	}
	сам.словАрена["миссии"] = миссии
	сам.ресурсы = stat_resurs.НовСтатРесурсы(сам)
	_ = types.ИАнгар(сам)
	return сам, nil
}

// Обновить -- обновить ангар принудительно
func (сам *Ангар) Обновить() {
	сам.РесурсыОбновить()
	ош := сам.сетьТанкСтат.Update()
	if ош != nil {
		сам.слог.Инфо("НовАнгар(): при обновлении статистики, ош=\n\t%w\n", ош)
		сам.бот.Сервер().Отменить()
		return
	}
	сам.словАрена["конвой"].Пуск()
	сам.ресурсы.Топливо().Обновить()
}

// Запускает обработку ангара
func (сам *Ангар) пуск() {
	{ // Запуск компонентов
		сам.танкПарам.Пуск()
		go сам.ресурсы.Топливо().Run()
	}
	фнЦикл := func() bool {
		сам.Обновить()
		// сам.конвойПроверить()
		if err := сам.ОбратВремяУст("01:00"); err != nil {
			сам.Отмена()
			log.Printf("Ангар.Run(): in update ICountTime, err=\n\t%v\n", err)
			return false
		}
		for _, арена := range сам.словАрена {
			арена.Пуск()
		}
		return true
	}
	go func() {
		ош := сам.ОбратВремяУст("01")
		if ош != nil {
			сам.слог.Ошибка("Ангар.Run(): in update ICountTime, ош=\n\t%w\n", ош)
			сам.бот.Сервер().Отменить()
			return
		}
		for {
			select {
			case <-сам.бот.Контекст().Done(): // Отмена контекста
				return
			case <-сам.ВремяОстат().КаналСиг(): // Метка времени
				if !фнЦикл() {
					return
				}
			default: // Запускается раз в минуту
				if !фнЦикл() {
					return
				}
				time.Sleep(time.Minute * 1)
			}
		}
	}()
}

// Обновляет ресурсы ангара
func (сам *Ангар) РесурсыОбновить() {
	сам.сеть.Обновить()
	сам.золотоНайти()
	сам.сереброНайти()
}

// IMissions -- возвращает ссылку на объект миссий
func (сам *Ангар) Миссии() types.ИМиссии {
	return сам.словАрена["миссии"].(types.ИМиссии)
}

// Сражение -- возвращает объект сражения
func (сам *Ангар) Сражение() types.ИСражениеСцена {
	return сам.словАрена["сражение"].(types.ИСражениеСцена)
}

// Конвой -- возвращает объект конвоя
func (сам *Ангар) Конвой() types.ИКонвой {
	return сам.словАрена["конвой"].(types.ИКонвой)
}

// Золото -- возвращает объект золота
func (сам *Ангар) Золото() types.ИСтатПарам {
	return сам.ресурсы.Золото()
}

// Топливо -- возвращает объект топлива
func (сам *Ангар) Топливо() types.ИСтатПарам {
	return сам.ресурсы.Топливо().Fuel()
}

// Уровень -- возвращает объект уровня игрока
func (сам *Ангар) Уровень() types.ИСтатПарам {
	return сам.уровень
}

// Прогресс -- возвращает прогресс уровня игрока
func (сам *Ангар) Прогресс() types.ИСтатПарам {
	return сам.progress
}

// ИгрокиОнлайн -- возвращает количество игроков онлайн
func (сам *Ангар) ИгрокиОнлайн() types.ИСтатПарам {
	return сам.игроковОнлайн
}

// СереброВсего -- возвращает объект всего серебра в ангаре
func (сам *Ангар) СереброВсего() types.ИСтатПарам {
	return сам.ресурсы.СереброВсего()
}

// СереброЗаработаноСессия -- возвращает объект серебра за сессию в ангаре
func (сам *Ангар) СереброЗаработаноСессия() types.ИСтатПарам {
	return сам.silverOnline
}

// СереброОбновить -- на основе фактического серебра -- обновляет выработанное серебро
func (сам *Ангар) СереброОбновить(silverFact int) {
	if сам.СереброВсего().Получ() == 0 { // Если запуск
		сам.СереброВсего().Уст(silverFact)
		return
	}
	if сам.СереброВсего().Получ() > silverFact { // Если потрачено серебро
		сам.СереброВсего().Уст(silverFact)
		return
	}
	if сам.СереброВсего().Получ() < silverFact { // Если заработано
		so := сам.silverOnline.Получ()
		sd := silverFact - сам.СереброВсего().Получ()
		сам.silverOnline.Уст(so + sd)
	}
	сам.СереброВсего().Уст(silverFact)
}

// База -- возвращает базу
func (сам *Ангар) База() types.ИБаза {
	return сам.словАрена["база"].(types.ИБаза)
}

/* Проверяет на исполнение конвоя
func (сам *Ангар) конвойПроверить() {
	var (
		strOut   string
		еслиНайдено   bool
		lstAngar = сам.СписПолучить()
	)
	for _, strOut = range lstAngar {
		if strings.Contains(strOut, `>Конвой</span>`) {
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено {
		return
	}
	if !strings.Contains(strOut, `<a class="simple-but border gray mb1" href="convoy"><span><span>Конвой</span></span></a>`) {
		return
	}
	сам.конвой.UpdateLst()
}
*/

// Ищет в теле текста ангара серебро
func (сам *Ангар) сереброНайти() {
	// _mt.Println("\tAngarNet.findSilver()")
	lstAngar := сам.СписПолучить()
	var strOut string
	for _, strSilver := range lstAngar {
		if strings.Contains(strSilver, `<img title="Серебро" `) {
			strOut = strSilver
			break
		}
	}
	// Выделить топливо
	lstSilver := strings.Split(strOut, `<img title="Серебро" alt="Серебро" src="/images/icons/silver.png?2"/> `)
	strSilver := lstSilver[1]
	iSilver, err := strconv.Atoi(strSilver)
	if err != nil {
		// log._rintf("ERRO AngarNet.findSilver(): silver(%v) not number, err=\n\t%v\n", strSilver, err)
		return
	}
	сам.СереброВсего().Уст(iSilver)
}

// Ищет в теле текста ангара золото
func (сам *Ангар) золотоНайти() {
	var (
		lstAngar    = сам.бот.Ангар().СписПолучить()
		strOut      string
		еслиНайдено bool
	)

	for _, strGold := range lstAngar {
		if strings.Contains(strGold, `<img title="Золото" `) {
			strOut = strGold
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено {
		return
	}
	// Выделить топливо
	lstGold := strings.Split(strOut, `<img title="Золото" alt="Золото" src="/images/icons/gold.png?2"/> `)
	strGold := lstGold[1]
	iGold, err := strconv.Atoi(strGold)
	if err != nil {
		// log._rintf("ERRO AngarNet.findGold(): gold(%v) not number, err=\n\t%v\n", strGold, err)
		return
	}
	сам.бот.Ангар().Золото().Уст(iGold)
}
