package battleon

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

	"wartank/pkg/components/section"
	"wartank/pkg/components/sectionnet"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/battle/battle_worker/battleon/health"
	"wartank/server/serv_bots/warbot/angar/battle/battle_worker/battleon/manevr"
	"wartank/server/serv_bots/warbot/angar/battle/battle_worker/battleon/shot"
	"wartank/server/serv_bots/warbot/angar/battle/battle_worker/battleon/shot/isshot"
)

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

// BattleOn -- непосредственно танкует в сражении
type BattleOn struct {
	*section.Section
	net            *sectionnet.SectionNet
	bot            types.ИБот
	ctxBattle      context.Context // Контекст сражения
	fnCancelBattle func()          // Функция отмены сражения

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

// NewBattleOn -- возвращает новый *BattleOn
func NewBattleOn(bot types.ИБот) (*BattleOn, error) {
	section, err := section.NewSection(bot, "Исполнитель сражения", `<title>Сражения</title>`)
	if err != nil {
		return nil, fmt.Errorf("NewBattleOn(): in create ISection, err=\n\t%w", err)
	}

	ctxBattle, fnCancelBattle := context.WithTimeout(bot.Сервер().CtxApp(), time.Second*305)
	sf := &BattleOn{
		Section:        section,
		bot:            bot,
		ctxBattle:      ctxBattle,
		fnCancelBattle: fnCancelBattle,
		login:          bot.Имя(),
		isShot:         isshot.NewIsShot(),
		chTick:         make(chan int, 2),
	}
	sf.net, err = sectionnet.NewSectionNet(sf, "http://wartank.ru/pve")
	if err != nil {
		return nil, fmt.Errorf("NewBattleOn(): in create *SectionNet, err=\n\t%w", err)
	}
	go sf.makeTick()
	go sf.run()
	return sf, nil
}

// Ежесекудный тик
func (sf *BattleOn) makeTick() {
	defer func() {
		close(sf.chTick)
	}()
	for {
		select {
		case <-sf.bot.Кнт().Done(): // Отмена контекста приложения
			sf.fnCancelBattle()
			return
		case <-sf.ctxBattle.Done(): // Битва закончилась
			return
		default:
			sf.chTick <- 1
			time.Sleep(time.Second * 1)
		}
	}
}

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

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

// Проверяет окончание сражения
func (sf *BattleOn) checkEnd() {
	// log._rintf("BattleOn.checkEnd()\n")
	fnPrintEnd := func() {
		sf.fnCancelBattle()
		// log._rintf("BattleOn.checkEnd(): сражение завершено\n")
	}

	if err := sf.net.UpdateLst(); err != nil {
		// log._rintf("WARN BattleOn.checkEnd(): при обновлении lstBattleOn, err=\n\t%v\n", err)
		fnPrintEnd()
		return
	}
	lstBattleOn := sf.СписПолучить()
	for _, strOut := range lstBattleOn { // Сражение ещё идёт
		if strings.Contains(strOut, `" class="simple-but gray"><span><span>ОБЫЧНЫЕ</span></span></a>`) {
			return
		}
	}
	// Сражение закончилось
	fnPrintEnd()
}

func (sf *BattleOn) МанёврНадоУст() {
	if sf.manevr == nil {
		return
	}
	sf.manevr.SetNeed()
}

// ВыстрелБлок -- признак запрета стрельбы при слабом здоровье
func (sf *BattleOn) ВыстрелБлок() *isshot.IsShot {
	return sf.isShot
}

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

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