package manevr

import (
	"context"
	"fmt"

	// "log"
	"strings"
	"time"

	"github.com/sirupsen/logrus"

	"wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/health/repairtime"
	"wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/manevr/ismanevr"

	// "wartank/internal/components/sound"
	"wartank/pkg/components/safebool"
	"wartank/pkg/types"
)

/*
	Пытается маневрировать после выстрела
*/

// Manevr -- маневрирует после выстрела
type Manevr struct {
	types.IDivWarOn // FIXME:
	isEnd           *safebool.SafeBool
	ctxEnd          context.Context
	isManevr        *ismanevr.IsManevr     // Возможность выполнить манёвр
	manevrTime      *repairtime.RepairTime // Время до востановления манёвра
	chTick          chan int               // Тики для поиска маневра
}

// NewManevr -- возвращает новый *Manevr
func NewManevr(divwar types.IDivWarOn, isDivWar *safebool.SafeBool) (*Manevr, error) {
	{ // Предусловия
		if divwar == nil {
			return nil, fmt.Errorf("NewManevr(): battle is nil")
		}
	}
	if isDivWar == nil {
		return nil, fmt.Errorf("NewManevr(): isBattle is nil")
	}
	sf := &Manevr{
		IDivWarOn:  divwar,
		ctxEnd:     divwar.Ctx(),
		isEnd:      isDivWar,
		isManevr:   ismanevr.NewIsManevr(),
		manevrTime: repairtime.NewRepairTime(),
		chTick:     make(chan int, 1),
	}
	_ = sf.manevrTime.Set("0") // При запуске боя есть возможность маневрировать
	go sf.makeTick()
	go sf.run()
	return sf, nil
}

// Генерирует тик для уменьшения времени ожидания восстановления возможности манёвра
func (sf *Manevr) makeTick() {
	defer func() {
		close(sf.chTick)
		// log._rintf("Manevr.makeTick(): сражение завершено\n")
	}()
	for {
		select {
		case <-sf.ctxEnd.Done():
			return
		default:
			if sf.manevrTime.Get() == 0 {
				sf.chTick <- 1
			}

			sf.manevrTime.Dec()
			time.Sleep(time.Second * 1)
		}
	}
}

// Рабочий цикл поиска маневра (~)
func (sf *Manevr) run() {
	for range sf.chTick {
		if !sf.isManevr.Get() {
			continue
		}
		sf.findManevrTime()
	}
}

// Ищет время для манёвра
func (sf *Manevr) findManevrTime() {
	var (
		isFind      bool
		ind         int
		lstBattleOn = sf.GetLst()
		strOut      string
	)
	for ind, strOut = range lstBattleOn {
		// <a href="pve?4-88.ILinkListener-currentControl-maneuverLink" class="simple-but blue"><span><span>5 секунд</span></span></a>
		if strings.Contains(strOut, `-currentControl-maneuverLink`) {
			isFind = true
			break
		}
	}
	if !isFind { // Или манёвр успел восстановиться, или конец сражения
		if strings.Contains(strOut, `<span>Маневр</span>`) {
			_ = sf.manevrTime.Set("0")
			time.Sleep(time.Second * 1)
			return
		}
		if sf.isEnd.Get() {
			time.Sleep(time.Second * 1)
			return
		}
		logrus.WithField("strOut", strOut).Warn("Manevr.findManevrTime(): ошибка в поиске времени манёвра")
		time.Sleep(time.Second * 1)
		return
	}
	{ // Найти время манёвра
		lstTime := strings.Split(strOut, `ILinkListener-currentControl-maneuverLink" class="simple-but blue"><span><span>`)
		if len(lstTime) != 2 {
			logrus.WithField("ind", ind).
				WithField("lstBattleOn[-1]", lstBattleOn[ind-1]).
				WithField("lstBattleOn[ind]", strOut).
				WithField("lstBattleOn[+1]", lstBattleOn[ind+1]).
				Errorf("Manevr.findManevrTime(): нет двух полей во времени ожидания")
			sf.isManevr.Reset()
			time.Sleep(time.Second * 1)
			return
		}
		strTime := lstTime[1]
		lstTime = strings.Split(strTime, ` секунд</span></span></a>`)
		strTime = lstTime[0]
		if err := sf.manevrTime.Set(strTime); err != nil {
			logrus.WithError(err).Error("Manevr.findManevrTime(): при обновлении времени ожидания манёвра")
			sf.isManevr.Reset()
			time.Sleep(time.Second * 1)
			return
		}
	}
	sf.isManevr.Set()
	logrus.WithField("время", sf.manevrTime.Get()).Info("Manevr.findManevrTime(): до манёвра")
}

// Manevr -- принудительный манёвр по требованию
func (sf *Manevr) Manevr() {
	var (
		isFind      = false
		lstBattleOn = sf.GetLst()
		strOut      = ""
	)
	if !sf.isManevr.Get() {
		time.Sleep(time.Second * 1)
		return
	}
	for _, strOut = range lstBattleOn {
		// <a href="pve?4-21.ILinkListener-currentControl-maneuverLink" class="simple-but blue"><span><span>Маневр</span></span></a>
		if strings.Contains(strOut, `<span>Маневр</span>`) {
			isFind = true
			break
		}
	}
	if !isFind { // Либо ждём восстановления манёвра, либо сражение закончилось
		sf.isManevr.Reset()
		time.Sleep(time.Second * 1)
		return
	}
	{ // Попытка манёвра
		lstLink := strings.Split(strOut, `<a href="`)
		strLink := lstLink[1]
		lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Маневр</span></span></a>`)
		strLink = "http://wartank.ru/" + lstLink[0]
		lstBattleOn, err := sf.Net().Get(strLink)
		if err != nil {
			logrus.WithError(err).Error("Manevr.Manevr(): при выполнении GET-команды маневра")
			sf.isManevr.Reset()
			time.Sleep(time.Second * 1)
			return
		}
		if err = sf.Update(lstBattleOn); err != nil {
			logrus.WithError(err).Error("Manevr.Manevr(): при обновлении lstBattle")
			sf.isManevr.Reset()
			time.Sleep(time.Second * 1)
			return
		}
		// sound.Manevr()
	}
}

// IsReady -- возвращает готовность манёвра
func (sf *Manevr) IsReady() bool {
	return sf.manevrTime.IsReady()
}
