package divwaron

import (
	"context"
	"fmt"
	"strings"
	"time"

	"wartank/pkg/components/safebool"
	"wartank/pkg/components/section"
	"wartank/pkg/components/sectionnet"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/health"
	"wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/manevr"
	"wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/shot"
)

/*
	Предоставляет сетевой компонент при непосредственном сражении
*/

// DivWarOn -- непосредственно танкует в сражении
type DivWarOn struct {
	*section.Section
	net            *sectionnet.SectionNet
	server         types.IServer
	ctxDivWar      context.Context // Контекст сражения
	fnCancelDivWar func()          // Функция отмены сражения

	shot      *shot.Shot     // Объект выстрела
	health    *health.Health // Текущее здоровье танка
	manevr    *manevr.Manevr // Возможность маневрирования
	login     string
	isMasking *safebool.SafeBool // Признак необходимости маскирования (запрет стрельбы, когда слабое здоровье)
	chTick    chan int           // Ежесекудная проверка на окончание сражения
	isEnd     *safebool.SafeBool
}

// NewDivWarOn -- возвращает новый *DivWarOn
func NewDivWarOn(server types.IServer, bot types.IServBot) (*DivWarOn, error) {
	{ // Предусловия
		if server == nil {
			return nil, fmt.Errorf("NewDivWarOn(): IServer == nil")
		}
		if bot == nil {
			return nil, fmt.Errorf("NewDivWarOn(): IServBot == nil")
		}
	}
	ctxDivWar, fnCancelDivWar := context.WithTimeout(server.CtxApp(), time.Second*305)
	sf := &DivWarOn{
		server:         server,
		ctxDivWar:      ctxDivWar,
		fnCancelDivWar: fnCancelDivWar,
		login:          bot.Name(),
		isMasking:      safebool.NewSafeBool(),
		isEnd:          safebool.NewSafeBool(),
	}
	var err error
	{ // ISection (ожидание)
		sf.Section, err = section.NewSection(server, `<title>Сражения</title>`)
		if err != nil {
			return nil, fmt.Errorf("NewDivWarOn(): in create *Section, err=\n\t%w", err)
		}
	}
	// sf.net = sectionnet.NewSectionNet(server, bot, "http://wartank.ru/pve")
	if sf.checkEnd() {
		return nil, fmt.Errorf("NewDivWarOn(): нет страницы для сражения")
	}
	go sf.makeTick()
	go sf.run()
	return sf, nil
}

// Ежесекудный тик
func (sf *DivWarOn) makeTick() {
	defer func() {
		close(sf.chTick)
		sf.isEnd.Set()
	}()
	for !sf.isEnd.Get() {
		select {
		case <-sf.server.Done(): // Отмена контекста приложения
			return
		case <-sf.ctxDivWar.Done(): // Битва закончилась
			return
		default:
			if sf.isEnd.Get() {
				return
			}
			sf.chTick <- 1
			time.Sleep(time.Second * 1)
		}
	}
}

// запускает сражение
func (sf *DivWarOn) run() {
	// defer log._rintf("DivWarOn.run(): сражение завершено\n")
	{ // Подготовка к сражению
		var err error
		sf.shot, err = shot.NewShot(sf, sf.login) // Объект выстрела
		if err != nil {
			// log._rintf("ERRO DivWarOn.Run(): при создании выстрела танка, err=\n\t%v\n", err)
			return
		}
		sf.health, err = health.NewHealth(sf, sf.shot.IsEnd(), sf.login)
		if err != nil {
			// log._rintf("ERRO DivWarOn.Run(): при создании здоровья танка, err=\n\t%v\n", err)
			sf.shot.IsEnd().Reset()
			return
		}
		sf.manevr, err = manevr.NewManevr(sf, sf.shot.IsEnd())
		if err != nil {
			// log._rintf("ERRO DivWarOn.Run(): при создании маневра танка, err=\n\t%v\n", err)
			sf.shot.IsEnd().Reset()
			return
		}
	}
	for { // Рабочий цикл сражения
		select {
		case <-sf.ctxDivWar.Done():
			return
		case <-sf.CountDown().ChanSig():
			if sf.checkEnd() {
				return
			}
		}
	}
}

// Net -- возвращает сетевой компонент секции
func (sf *DivWarOn) Net() types.ISectionNet {
	return sf.net
}

// Проверяет окончание сражения
func (sf *DivWarOn) checkEnd() bool {
	defer func() {
		if sf.isEnd.Get() {
			sf.fnCancelDivWar()
			// log._rintf("DivWarOn.checkEnd(): сражение завершено\n")
		}
	}()

	if err := sf.net.UpdateLst("Битва дивизий+"); err != nil {
		// log._rintf("WARN DivWarOn.checkEnd(): при обновлении lstDivWarOn, err=\n\t%v\n", err)
		sf.isEnd.Set()
		sf.fnCancelDivWar()
		return true
	}
	lstDivWarOn := sf.GetLst()
	for _, strOut := range lstDivWarOn {
		if strings.Contains(strOut, `" class="simple-but gray"><span><span>ОБЫЧНЫЕ</span></span></a>`) {
			sf.isEnd.Reset()
			return false
		}
	}
	sf.isEnd.Set()
	sf.fnCancelDivWar()
	return true
}

// IsEnd -- возвращает признак окончания сражения (интерфейс)
func (sf *DivWarOn) IsEnd() *safebool.SafeBool {
	return sf.isEnd
}

func (sf *DivWarOn) Manevr() {
	if sf.manevr == nil {
		return
	}
	if sf.manevr.IsReady() {
		sf.manevr.Manevr()
	}
}

// Masking -- признак запрета стрельбы при слабом здоровье
func (sf *DivWarOn) Masking() *safebool.SafeBool {
	return sf.isMasking
}

// Ctx -- возвращает контекст отмены сражения
func (sf *DivWarOn) Ctx() context.Context {
	return sf.ctxDivWar
}

// CancelBattle - -вызов функции отмены контекста сражения
func (sf *DivWarOn) CancelBattle() {
	sf.fnCancelDivWar()
}
