package polygon

import (
	"fmt"
	"strconv"
	"strings"

	"wartank/pkg/components/section"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/base/polygon/polygonnet"
)

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

// Polygon -- объект полигона на базе
type Polygon struct {
	*section.Section
	server   types.IServer
	bot      types.IServBot
	tankStat types.ITankStat
	net      *polygonnet.PolygonNet
}

// NewPolygon -- возвращает новый *Polygon
func NewPolygon(server types.IServer, bot types.IServBot) (*Polygon, error) {
	if server == nil {
		return nil, fmt.Errorf("NewPolygon(): IServer == nil")
	}
	if bot == nil {
		return nil, fmt.Errorf("NewPolygon(): IServBot == nil")
	}
	sf := &Polygon{
		server:   server,
		bot:      bot,
		tankStat: bot.Tank().TankStat(),
	}

	return sf, nil
}

func (sf *Polygon) Run() error {
	var err error
	{ // Секция
		sf.Section, err = section.NewSection(sf.server, `<title>Полигон</title>`)
		if err != nil {
			return fmt.Errorf("Polygon.Run(): in create *Section, err=\n\t%w", err)
		}
	}
	{ // Polygon
		sf.net, err = polygonnet.NewPolygonNet(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Polygon.Run(): in create NetPolygon, err=\n\t%w", err)
		}
	}
	go sf.run()
	return nil
}

// выполняет опрос полигона базы.
func (sf *Polygon) run() {
	sf.CountDown().Set(2)
	for {
		select {
		case <-sf.server.Done():
			sf.CountDown().Stop()
			return
		case <-sf.CountDown().ChanSig():
			mode := sf.ModeCurrent().Get()
			if mode == "upgrade" {
				continue
			}
			sf.addForce()
			sf.checkForce()
			sf.updateTime()
		}
	}
}

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

// Проверяет что именно активировано
func (sf *Polygon) checkForce() {
	var (
		isFind     bool
		lstPolygon = sf.GetLst()
		ind        = 0
		strOut     string
	)

	for ind, strOut = range lstPolygon {
		if strings.Contains(strOut, `<span>Активно</span>`) {
			ind -= 9
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	strOut = lstPolygon[ind]
	switch { // Вычисляем контрольную строку
	case strings.Contains(strOut, `>улучшение точности<`):
		sf.tankStat.Force().SetName("fyne")
	case strings.Contains(strOut, `>увеличение прочности<`):
		sf.tankStat.Force().SetName("hard")
	case strings.Contains(strOut, `>усиление брони<`):
		sf.tankStat.Force().SetName("armor")
	case strings.Contains(strOut, `>усиление атаки<`):
		sf.tankStat.Force().SetName("attack")
	}
	// Вычислим на сколько
	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
	}
	sf.tankStat.Force().Set(iForce)
}

// Выбирает самый слабый параметр и усиливает его
func (sf *Polygon) addForce() {
	if err := sf.net.UpdateLst("Полигон"); err != nil {
		// log._rintf("Polygon.checkPolygon(): при принудительном обновлении lstPlygon, mode=%s\terr=\n\t%v\n", sf.ModeCurrent().Get(), err)
		sf.CountDown().Set(5)
		return
	}
	lstPoligon := sf.GetLst()
	if len(lstPoligon) == 0 {
		return
	}
	stat := sf.tankStat
	iAttack := stat.Attack().Get()
	iArmor := stat.Armor().Get()
	iFyne := stat.Fyne().Get()
	iHard := stat.Hard().Get()

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

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

		if iArmor <= iParam {
			iParam = iArmor
			strParam = "armor"
		}
		if iFyne <= iParam {
			iParam = iFyne
			strParam = "fyne"
		}
		if iAttack < iParam {
			strParam = "attack"
		}
	}

	// Найти нужную строку активации
	var (
		ind    int
		strOut string
		isFind bool
	)
	switch strParam {
	case "attack": // Усиливаем атаку
		for ind, strOut = range lstPoligon {
			if strings.Contains(strOut, `>усиление атаки<`) {
				isFind = true
				break
			}
		}
		if !isFind {
			return
		}
		ind += 8
		strOut = lstPoligon[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 := "http://wartank.ru/" + lstLink[0]
		if _, err := sf.net.Get(strLink); err != nil {
			// log._rintf("ERRO NetPolygon.addForce(): in make request force attack, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована атака
			strForce := lstPoligon[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
			}
			sf.tankStat.Force().Set(iForce)
			sf.tankStat.Force().SetName("attack")
			sf.ModeCurrent().Set("атака")
		}
	case "armor": // Усиливаем броню
		isFind = false
		for ind, strOut = range lstPoligon {
			if strings.Contains(strOut, `>усиление брони<`) {
				isFind = true
				break
			}
		}
		if !isFind {
			return
		}
		ind += 8
		strOut = lstPoligon[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 := "http://wartank.ru/" + lstLink[0]
		if _, err := sf.net.Get(strLink); err != nil {
			// log._rintf("NetPolygon.addForce(): in make request force armor, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована броня
			strForce := lstPoligon[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
			}
			sf.tankStat.Force().Set(iForce)
			sf.tankStat.Force().SetName("armor")
			sf.ModeCurrent().Set("броня")
		}
	case "fyne": // Усиливаем точность
		isFind = false
		for ind, strOut = range lstPoligon {
			if strings.Contains(strOut, `>улучшение точности<`) {
				isFind = true
				break
			}
		}
		if !isFind {
			return
		}
		ind += 8
		strOut = lstPoligon[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 := "http://wartank.ru/" + lstLink[0]
		if _, err := sf.net.Get(strLink); err != nil {
			// log._rintf("ERRO NetPolygon.addForce(): in make request force fyne, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована точность
			strForce := lstPoligon[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
			}
			sf.tankStat.Force().Set(iForce)
			sf.tankStat.Force().SetName("fyne")
			sf.ModeCurrent().Set("точность")
		}
	case "hard": // Усиливаем мощность
		isFind = false
		for ind, strOut = range lstPoligon {
			if strings.Contains(strOut, `>увеличение прочности<`) {
				isFind = true
				break
			}
		}
		if !isFind {
			return
		}
		ind += 8
		strOut = lstPoligon[ind]
		lstLink := strings.Split(strOut, `<a class="simple-but border" href="`)
		strOut = lstLink[1]
		lstLink = strings.Split(strOut, `"><span><span>Получить бесплатно</span></span></a>`)
		strLink := "http://wartank.ru/" + lstLink[0]
		if _, err := sf.net.Get(strLink); err != nil {
			// log._rintf("NetPolygon.addForce(): in make request force hard, err=\n\t%v\n", err)
			return
		}
		{ // Узнать на сколько форсирована прочность
			strForce := lstPoligon[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
			}
			sf.tankStat.Force().Set(iForce)
			sf.tankStat.Force().SetName("hard")
			sf.ModeCurrent().Set("прочность")
		}
	default: // Неизвестно что
		sf.ModeCurrent().Set("неизвестно")
		// log._rintf("ERRO NetPolygon.addForce(): неизвестно что это, strParam=%q", strParam)
		return
	}
}
