package polygon

import (
	"log"
	"strconv"
	"strings"
	"time"
	"wartank/pkg/alias"
	"wartank/pkg/arena"
	"wartank/pkg/components/arena_net"
	"wartank/pkg/components/kernel/logger"
	"wartank/pkg/components/safe_int"
	"wartank/pkg/components/safe_string"
	"wartank/pkg/cons"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/stat_tank/static_param"
)

/*
	Объект полигона на базе
*/

const (
	времОжидПлат    = "05:00" // Время ожидания платного ускорения
	времОжидБесплат = "30:00" // Время ожидания бесплатного ускорения
	стрПрочность    = "прочность"
	стрТочность     = "точность"
	стрБроня        = "броня"
	стрАтака        = "атака"
)

// Полигон -- объект полигона на базе
type Полигон struct {
	types.ИАрена
	бот           types.ИБот
	танкСтат      types.ИТанкСтат
	сеть          types.ИАренаСеть
	продуктСейчас *safe_string.БезопСтрока
	продуктКол    *safe_int.БезопЦелое
	уровень       *static_param.СтатПарам
	лог           types.ИЛоггер
}

// НовПолигон -- возвращает новый *Polygon
func НовПолигон(база types.ИБаза) *Полигон {
	лог := logger.НовЛоггер("Полигон " + база.Бот().Имя())
	лог.Инфо("НовПолигон(): бот=%s\n", база.Бот().Имя())
	сам := &Полигон{
		бот:           база.Бот(),
		танкСтат:      база.Бот().Стата(),
		продуктСейчас: safe_string.НовБезопСтрока(),
		продуктКол:    safe_int.НовБезопЦелое(),
		уровень:       static_param.НовСтатПарам("уровень полигона"),
		лог:           лог,
	}
	аренаКонфиг := arena.АренаКонфиг{
		Бот_:         база.Бот(),
		АренаИмя_:    "Полигон",
		СтрКонтроль_: `<span class="green2">Полигон</span><br/>`,
		ФнПуск_:      сам.пуск,
		СтрУрл_:      "https://wartank.ru/polygon",
	}
	сам.ИАрена = arena.НовАрена(аренаКонфиг)
	сам.сеть = arena_net.НовАренаСеть(сам, "https://wartank.ru/polygon")
	_ = types.ИБазаПолигон(сам)
	return сам
}

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

// ПродуктКолСейчас -- количество продукта, что именно сейчас производится на полигоне
func (сам *Полигон) ПродуктКолСейчас() int {
	return сам.продуктКол.Получ()
}

// ПродуктИмяСейчас -- что именно сейчас производится на полигоне
func (сам *Полигон) ПродуктИмяСейчас() string {
	return сам.продуктСейчас.Получ()
}

// ПродуктВремяСейчас -- сколько осталось времени до обновы полигона
func (сам *Полигон) ПродуктВремяСейчас() string {
	return сам.ВремяОстат().String()
}

// Пуск -- запускает работу полигона в отдельном потоке
func (сам *Полигон) Пуск() error {
	go сам.пуск()
	return nil
}

const (
	стрАпгрейд = "апгрейд"
)

// выполняет опрос полигона базы.
func (сам *Полигон) пуск() {
	ош := сам.ОбратВремяУст("02")
	if ош != nil {
		log.Printf("Полигон(): при установке времени обратного отсчета, ош=\n\t%v\n", ош)
		сам.бот.Сервер().Отменить()
		return
	}
	фнРабота := func() {
		defer func() {
			for сам.ВремяОстат().ПолучМилСек() > 0 {
				select {
				case <-сам.Контекст().Done():
					return
				default:
					time.Sleep(time.Second * 5)
				}
			}
		}()
		if сам.построитьПровер() { // Можно ли посторить?
			if сам.построить() {
				return
			}
		}
		сам.проверитьУскорение()
		сам.усилениеДобавить()
		сам.усилениеПровер()
		сам.времяОбнов()

		if сам.продуктСейчас.Получ() == стрАпгрейд {
			ош := сам.ВремяОстат().Уст("00:10:00")
			if ош != nil {
				log.Printf("Полигон(): при установке времени обратного отсчета, ош=\n\t%v\n", ош)
				сам.бот.Сервер().Отменить()
				return
			}
		}
		счёт := 5
		for счёт > 0 {
			if сам.уровеньПолучить() {
				break
			}
			счёт--
		}
		log.Printf("Полигон.пуск(): бот=%q, цикл завершён\n", сам.бот.Имя())
	}
	for {
		select {
		case <-сам.Контекст().Done():
			return
		case <-сам.ВремяОстат().КаналСиг():
			фнРабота()
		default:
			фнРабота()
		}
	}
}

// Построить
func (сам *Полигон) построить() bool {
	списСтр := сам.сеть.ВебВоркер().Получ("https://wartank.ru/building-upgrade/Polygon")
	ссылка0 := "" // ссылка на постройку

	{ // Поиск ссылки на покупку
		for _, стр := range списСтр {
			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
				ссылка0 = стр
				break
			}
		}
		if ссылка0 == "" {
			return false
		}
		// <a class="simple-but border mb5" href="Polygon?9-1.ILinkListener-upgradeLink-link">
		ссылка0 = strings.TrimPrefix(ссылка0, `<a class="simple-but border mb5" href="`)
		ссылка0 = strings.TrimSuffix(ссылка0, `">`)
		// https://wartank.ru/building-upgrade/Polygon?40-1.ILinkListener-upgradeLink-link
		ссылка0 = "http://wartank.ru/building-upgrade/" + ссылка0
		списСтр = сам.сеть.ВебВоркер().Получ(ссылка0)
	}
	ссылка1 := "" // ссылка на улучшение здания

	{ // Выбор покупки
		// <a class="simple-but border mb5" href="Polygon?49-1.ILinkListener-upgradeLink-link">
		for _, стр := range списСтр {
			if strings.Contains(стр, `ILinkListener-upgradeLink-link`) {
				ссылка1 = стр
				break
			}
		}
		if ссылка1 == "" {
			return false
		}
		ссылка1 = strings.TrimPrefix(ссылка1, `<a class="simple-but border mb5" href="`)
		ссылка1 = strings.TrimSuffix(ссылка1, `">`)
		// https://wartank.ru/building-upgrade/Polygon?48-1.ILinkListener-upgradeLink-link
		ссылка1 = "http://wartank.ru/building-upgrade/" + ссылка1
		списСтр = сам.сеть.ВебВоркер().Получ(ссылка1)
	}
	ссылка2 := "" // подтверждение покупки
	{             // Подтверждение покупки
		// <a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../wicket/page?53-1.ILinkListener-confirmLink"><span><span>да, подтверждаю</span></span></a>
		for _, стр := range списСтр {
			if strings.Contains(стр, `confirmLink`) {
				ссылка2 = стр
				break
			}
		}
		if ссылка2 == "" {
			return false
		}
		ссылка2 = strings.TrimPrefix(ссылка2, `<a class="simple-but border w50 mXa mb10" w:id="confirmLink" href="../`)
		ссылка2 = strings.TrimSuffix(ссылка2, `">`)
		// https://wartank.ru/wicket/page?52-1.ILinkListener-confirmLink
		ссылка2 = "http://wartank.ru/wicket/" + ссылка2
		//ссылка2="https://wartank.ru/wicket/page?25-1.ILinkListener-confirmLink"
		_ = сам.сеть.ВебВоркер().Получ(ссылка2)
	}
	return true
}

// Проверяет уровень полигона
func (сам *Полигон) уровеньПолучить() bool {
	var (
		стрВых      = ""
		еслиНайдено bool
	)
	lstBase := сам.сеть.ВебВоркер().Получ("https://wartank.ru/buildings")
	// <span class="green2">Полигон - 5</span><br/>
	for _, стрВых = range lstBase {
		if strings.Contains(стрВых, `<span class="green2">Полигон - `) {
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено {
		return false
	}
	стрУровень := strings.TrimPrefix(стрВых, `<span class="green2">Полигон - `)
	стрУровень = strings.TrimSuffix(стрУровень, `</span><br/>`)
	цУров, ош := strconv.Atoi(стрУровень)
	if ош != nil {
		return false
	}
	сам.уровень.Уст(цУров)
	return true
}

// Проверяет на ускорение апгрейда полигона
func (сам *Полигон) проверитьУскорение() bool {
	var (
		strOut      = ""
		еслиНайдено bool
	)
	lstBase := сам.сеть.ВебВоркер().Получ("https://wartank.ru/buildings")
	// Проверка на платное ускорение апгрейда + время
	{ // Платное ускорение
		if strings.Contains(strOut, `Ускорить за`) {
			if err := сам.ОбратВремяУст(времОжидПлат); err != nil {
				log.Printf("WARN Base.checkArsenalForce(): при установке платного времени ускорения апгрейда арсенала(%v)\n\terr=%v\n", времОжидПлат, err)
			}
			сам.АренаСостояние().РаботаИмяУст("")
			сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
			сам.продуктСейчас.Уст(стрАпгрейд)
			сам.продуктКол.Уст(0)
			return true
		}
	}
	{ // Проверка на бесплатное ускорение апгрейда
		еслиНайдено = false
		for _, strOut = range lstBase {
			if strings.Contains(strOut, `Производит снаряды, ремкомплекты<br/>`) {
				// Убедиться что есть строка платного ускорения
				еслиНайдено = true
				break
			}
		}
		if !еслиНайдено {
			return false
		}
		if !strings.Contains(strOut, `>Ускорение<`) {
			return false
		}
		сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
		сам.продуктСейчас.Уст(стрАпгрейд)
		сам.продуктКол.Уст(0)
		lstLink := strings.Split(strOut, `<td style="width:50%;padding-left:1px;"><a class="simple-but border" href="`)
		strLink := lstLink[1]
		lstLink = strings.Split(strLink, `"><span><span>Ускорение</span></span></a>`)
		strLink = "https://wartank.ru/" + lstLink[0]
		lstBase, err := сам.сеть.Get(strLink)
		if err != nil {
			// log._rintf("ERRO NetBank.checkArsenalForce(): при GET-запросе на бесплатном ускорении апгрейда арсенала, err=\n\t%v\n", err)
			return false
		}
		// sound.ArsenalForce()
		if err := сам.СтрОбновить(lstBase); err != nil {
			// log._rintf("ERRO NetBank.checkArsenalForce(): при обновлении lstBase, err=\n\t%v\n", err)
			return false
		}
		сам.АренаСостояние().РаботаИмяУст("")
		сам.АренаСостояние().СостояниеУст(cons.РежимАпгрейд)
		сам.продуктКол.Уст(0)
		if err := сам.ОбратВремяУст(времОжидБесплат); err != nil {
			log.Printf("WARN Base.checkArsenalForce(): при установке бесплатного времени ускорения апгрейда арсенала(%v)\n\terr=%v\n", времОжидБесплат, err)
		}
	}
	// Все проверки прошли -- это просто работа
	сам.АренаСостояние().РаботаИмяУст("work")
	return true
}

// Проверяет необходимость постройки полигона
func (сам *Полигон) построитьПровер() bool {
	// https://wartank.ru/building-upgrade/Polygon
	списПолигон := сам.сеть.ВебВоркер().Получ("https://wartank.ru/building-upgrade/Polygon")
	стрСсылка := ""
	еслиНайти := false
	// <a class="simple-but border mb5" href="Polygon?66-1.ILinkListener-upgradeLink-link">
	for _, стрСсылка = range списПолигон {
		if strings.Contains(стрСсылка, `href="Polygon?`) {
			еслиНайти = true
			break
		}
	}
	return еслиНайти
}

// Обновляет оставшееся время полигона
//
//	Этот объект сам описывает своё время
func (сам *Полигон) времяОбнов() {
	var (
		strLastTime string
		еслиНайдено bool
		isSet       bool
		lstPolygon  = сам.СписПолучить()
	)
	defer func() {
		if !isSet {
			ош := сам.ОбратВремяУст("05")
			if ош != nil {
				log.Printf("Полигон.времяОбнов(): при установке обратного времени ожидания полигона, ош=\n\t%v\n", ош)
				сам.бот.Сервер().Отменить()
				return
			}
		}
	}()
	for _, lastTime := range lstPolygon {
		if strings.Contains(lastTime, `>Осталось: `) {
			strLastTime = lastTime
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено { // Время полигона вышло
		return
	}
	lstTime := strings.Split(strLastTime, `>Осталось: `)
	strLastTime = lstTime[1]
	lstTime = strings.Split(strLastTime, `</span>`)
	strLastTime = lstTime[0]
	if err := сам.ОбратВремяУст(alias.Время(strLastTime)); err != nil {
		// log._rintf("ERRO Polygon.updateTime(): при установке времени ожидания полигона(%v)\n\terr=%v\n", strLastTime, err)
		return
	}
	isSet = true
}

// Проверяет что именно активировано
func (сам *Полигон) усилениеПровер() {
	var (
		еслиНайдено bool
		lstPolygon  = сам.СписПолучить()
		ind         = 0
		strOut      string
	)

	for ind, strOut = range lstPolygon {
		if strings.Contains(strOut, `<span>Активно</span>`) {
			ind -= 9
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено {
		return
	}
	strOut = lstPolygon[ind]
	форсажИмя := ""
	switch { // Вычисляем контрольную строку
	case strings.Contains(strOut, `>улучшение точности<`):
		форсажИмя = стрТочность
	case strings.Contains(strOut, `>увеличение прочности<`):
		форсажИмя = стрПрочность
	case strings.Contains(strOut, `>усиление брони<`):
		форсажИмя = стрБроня
	case strings.Contains(strOut, `>усиление атаки<`):
		форсажИмя = стрАтака
	}
	// Вычислим на сколько
	strOut = lstPolygon[ind+1]
	lstOut := strings.Split(strOut, `<span class="green2">+`)
	strOut = lstOut[1]
	lstOut = strings.Split(strOut, ` на `)
	strOut = lstOut[0]
	iForce, err := strconv.Atoi(strOut)
	if err != nil {
		// log._rintf("NetPolygon.checkTime(): force(%v) not number, err=\n\t%v\n", strOut, err)
		return
	}
	сам.танкСтат.ФорсажОбнов(форсажИмя, iForce)
	сам.продуктСейчас.Уст("усиление-" + форсажИмя)
	сам.продуктКол.Уст(iForce)
}

// Выбирает самый слабый параметр и усиливает его
func (сам *Полигон) усилениеДобавить() {
	сам.сеть.Обновить()
	// log._rintf("Polygon.checkPolygon(): при принудительном обновлении lstPolygon, mode=%s\terr=\n\t%v\n", сам.ModeCurrent().Get(), err)
	if err := сам.ОбратВремяУст("05"); err != nil {
		log.Printf("Polygon.checkPolygon(): при принудительном обновлении обратного времени, время=`05`\terr=\n\t%v\n", err)
		сам.бот.Сервер().Отменить()
		return
	}
	lstPolygon := сам.СписПолучить()
	if len(lstPolygon) == 0 {
		return
	}
	stat := сам.танкСтат
	iAttack := stat.Атака().Получ()
	iArmor := stat.Броня().Получ()
	iFyne := stat.Точность().Получ()
	iHard := stat.Прочность().Получ()

	strParam := стрАтака
	iParam := iHard
	{
		/*
			Вычислить самый слабый параметр.

			Политика вычислений:
				1) hard -- прочность, самый низкоприоритетный параметр
				2) armor -- броня, чуть лучше power
				3) fyne -- точность, чуть лучше armor
				4) attack -- атака, самый важный
		*/

		if iArmor <= iParam {
			iParam = iArmor
			strParam = стрБроня
		}
		if iFyne <= iParam {
			iParam = iFyne
			strParam = стрТочность
		}
		if iAttack < iParam {
			strParam = стрАтака
		}
	}

	// Найти нужную строку активации
	var (
		ind         int
		strOut      string
		еслиНайдено bool
	)
	switch strParam {
	case стрАтака: // Усиливаем атаку
		for ind, strOut = range lstPolygon {
			if strings.Contains(strOut, `>усиление атаки<`) {
				еслиНайдено = true
				break
			}
		}
		if !еслиНайдено {
			return
		}
		ind += 8
		strOut = lstPolygon[ind]
		if strOut == "" {
			return
		}
		lstLink := strings.Split(strOut, `<a class="simple-but border" href="`)
		strOut = lstLink[1]
		lstLink = strings.Split(strOut, `"><span><span>Получить бесплатно</span></span></a>`)
		strLink := "https://wartank.ru/" + lstLink[0]
		if _, err := сам.сеть.Get(strLink); err != nil {
			// log._rintf("ERRO NetPolygon.addForce(): in make request force attack, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована атака
			strForce := lstPolygon[ind-7]
			lstForce := strings.Split(strForce, `<span class="green2">+`)
			strForce = lstForce[1]
			lstForce = strings.Split(strForce, ` на `)
			strForce = lstForce[0]
			iForce, err := strconv.Atoi(strForce)
			if err != nil {
				// log._rintf("ERRO NetPolygon.addForce(): strForceAttack(%v) not int, err=\n\t%v\n", strForce, err)
				return
			}
			сам.танкСтат.ФорсажОбнов("attack", iForce)
			сам.АренаСостояние().РаботаИмяУст(стрАтака)
		}
	case стрБроня: // Усиливаем броню
		еслиНайдено = false
		for ind, strOut = range lstPolygon {
			if strings.Contains(strOut, `>усиление брони<`) {
				еслиНайдено = true
				break
			}
		}
		if !еслиНайдено {
			return
		}
		ind += 8
		strOut = lstPolygon[ind]
		if strOut == "" {
			return
		}
		lstLink := strings.Split(strOut, `<a class="simple-but border" href="`)
		strOut = lstLink[1]
		lstLink = strings.Split(strOut, `"><span><span>Получить бесплатно</span></span></a>`)
		strLink := "https://wartank.ru/" + lstLink[0]
		if _, err := сам.сеть.Get(strLink); err != nil {
			// log._rintf("NetPolygon.addForce(): in make request force armor, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована броня
			strForce := lstPolygon[ind-7]
			lstForce := strings.Split(strForce, `<span class="green2">+`)
			strForce = lstForce[1]
			lstForce = strings.Split(strForce, ` на `)
			strForce = lstForce[0]
			iForce, err := strconv.Atoi(strForce)
			if err != nil {
				// log._rintf("ERRO NetPolygon.addForce(): strForceArmor(%v) not int, err=\n\t%v\n", strForce, err)
				return
			}
			сам.танкСтат.ФорсажОбнов(стрБроня, iForce)
			сам.АренаСостояние().РаботаИмяУст(стрБроня)
		}
	case стрТочность: // Усиливаем точность
		еслиНайдено = false
		for ind, strOut = range lstPolygon {
			if strings.Contains(strOut, `>улучшение точности<`) {
				еслиНайдено = true
				break
			}
		}
		if !еслиНайдено {
			return
		}
		ind += 8
		strOut = lstPolygon[ind]
		if strOut == "" {
			return
		}
		lstLink := strings.Split(strOut, `<a class="simple-but border" href="`)
		strOut = lstLink[1]
		lstLink = strings.Split(strOut, `"><span><span>Получить бесплатно</span></span></a>`)
		strLink := "https://wartank.ru/" + lstLink[0]
		if _, err := сам.сеть.Get(strLink); err != nil {
			// log._rintf("ERRO NetPolygon.addForce(): in make request force fyne, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована точность
			strForce := lstPolygon[ind-7]
			lstForce := strings.Split(strForce, `<span class="green2">+`)
			strForce = lstForce[1]
			lstForce = strings.Split(strForce, ` на `)
			strForce = lstForce[0]
			iForce, err := strconv.Atoi(strForce)
			if err != nil {
				// log._rintf("ERRO NetPolygon.addForce(): strForceFyne(%v) not int, err=\n\t%v\n", strForce, err)
				return
			}
			сам.танкСтат.ФорсажОбнов(стрТочность, iForce)
			сам.АренаСостояние().РаботаИмяУст(стрТочность)
		}
	case стрПрочность: // Усиливаем мощность
		еслиНайдено = false
		for ind, strOut = range lstPolygon {
			if strings.Contains(strOut, `>увеличение прочности<`) {
				еслиНайдено = true
				break
			}
		}
		if !еслиНайдено {
			return
		}
		ind += 8
		strOut = lstPolygon[ind]
		lstLink := strings.Split(strOut, `<a class="simple-but border" href="`)
		strOut = lstLink[1]
		lstLink = strings.Split(strOut, `"><span><span>Получить бесплатно</span></span></a>`)
		strLink := "https://wartank.ru/" + lstLink[0]
		if _, err := сам.сеть.Get(strLink); err != nil {
			// log._rintf("NetPolygon.addForce(): in make request force hard, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована прочность
			strForce := lstPolygon[ind-7]
			lstForce := strings.Split(strForce, `<span class="green2">+`)
			strForce = lstForce[1]
			lstForce = strings.Split(strForce, ` на `)
			strForce = lstForce[0]
			iForce, err := strconv.Atoi(strForce)
			if err != nil {
				// log._rintf("ERRO NetPolygon.addForce(): strForceHard(%v) not int, err=\n\t%v\n", strForce, err)
				return
			}
			сам.танкСтат.ФорсажОбнов(стрПрочность, iForce)
			сам.АренаСостояние().РаботаИмяУст(стрПрочность)
		}
	default: // Неизвестно что
		сам.АренаСостояние().РаботаИмяУст("неизвестно")
		// log._rintf("ERRO NetPolygon.addForce(): неизвестно что это, strParam=%q", strParam)
		return
	}
}
