package div_war

import (
	"fmt"
	"log"
	"strings"
	"sync"
	"time"
	"wartank/pkg/alias"
	"wartank/pkg/arena"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/division/div_war/div_war_net"
	"wartank/server/serv_bots/warbot/angar/division/div_war/div_war_on"
	"wartank/server/serv_bots/warbot/angar/division/div_war/div_war_on/div_war_sound"
	"wartank/server/serv_bots/warbot/stat_tank/static_param"
)

/*
	Объект ожидания битвы дивизий
*/

// DivWar -- объект ожидания битвы дивизий
type DivWar struct {
	types.ИАрена
	bot   types.ИБот
	alarm types.ИСтатПарам
	net   *div_war_net.DivWarNet
	conn  types.ИХттпВоркер

	// Непосредственная битва
	divOn *div_war_on.DivWarOn
	login string // Для непосредственной битвы дивизий
	block sync.Mutex

	chDivWar chan int // Сигнал начала битвы дивизий

	sound *div_war_sound.DivWarSound // Однопоточное проигрывание звука
}

// NewDivWar -- возвращает новый *DivWar
func NewDivWar(bot types.ИБот) (*DivWar, error) {
	if bot == nil {
		return nil, fmt.Errorf("NewDivWar(): IBot == nil")
	}
	сам := &DivWar{
		bot:      bot,
		alarm:    static_param.НовСтатПарам("alarm"),
		chDivWar: make(chan int, 1),
		sound:    div_war_sound.NewDivWarSound(),
		conn:     bot.Сеть().ВебВоркер(),
		login:    "prospero tank",
	}
	аренаКонфиг := arena.АренаКонфиг{
		Бот_:         bot,
		АренаИмя_:    "Битва дивизий",
		СтрКонтроль_: `<span>до начала `,
		ФнПуск_:      сам.пуск,
	}
	сам.ИАрена = arena.НовАрена(аренаКонфиг)
	// сам.shotTimeFull.Set(8000) // 8000 msec
	var err error
	{ // Net
		сам.net, err = div_war_net.NewDivWarNet(bot)
		if err != nil {
			return nil, fmt.Errorf("NewDivWar(): при создании DivWarNet, err=\n\t%w", err)
		}
	}
	go сам.run()
	go сам.резервТик()
	return сам, nil
}

// запускает в работу битву дивизий
func (сам *DivWar) пуск() {
}

func (сам *DivWar) резервТик() {
	for {
		select {
		case <-сам.bot.Контекст().Done():
			return
		default:
			ct0 := сам.ВремяОстат().ПолучМилСек()
			time.Sleep(time.Second * 7)
			ct1 := сам.ВремяОстат().ПолучМилСек()
			if ct1.Сек() != ct0.Сек() {
				continue
			}
			if сам.divOn != nil {
				continue
			}
			сам.chDivWar <- 1
		}
	}
}

// запускает в работу битву дивизий
func (сам *DivWar) run() {
	сам.chDivWar <- 1
	for {
		select {
		case <-сам.bot.Контекст().Done():
			return
		case <-сам.ВремяОстат().КаналСиг(): // Время обновить данные по сражению
			сам.findTimeCount()
			сам.upDivWar()
		case <-сам.chDivWar: // Сигнал к началу сражения
			сам.block.Lock()
			if сам.divOn != nil {
				continue
			}
			сам.alarm.Уст(1)
			сам.sound.Play()
			go сам.DivWar()              // Запустить цикл непосредственного сражения
			time.Sleep(time.Second * 10) // Задержка для звука на странице
			сам.alarm.Уст(0)
		}
	}
}

// Ищет время до начала битвы дивизий
func (сам *DivWar) findTimeCount() {
	сам.net.Обновить()
	var (
		strOut      string
		lstDivWar   = сам.СписПолучить()
		еслиНайдено bool
		ind         int
	)
	for ind, strOut = range lstDivWar {
		if strings.Contains(strOut, `до начала: `) {
			ind++
			strOut = lstDivWar[ind]
			еслиНайдено = true
			break
		}
		if strings.Contains(strOut, `>ОБЫЧНЫЕ<`) { // Это уже битва
			сам.chDivWar <- 1
			return
		}
	}
	if !еслиНайдено { // Битва дивизий уже идёт
		сам.chDivWar <- 1
		return
	}
	lstTime := strings.Split(strOut, `<span>`)
	strTime := lstTime[1]
	lstTime = strings.Split(strTime, `</span>`)
	strTime = lstTime[0]
	if err := сам.ОбратВремяУст(alias.Время(strTime)); err != nil {
		// log._rintf("WARN DivWar.findTimeCount(): при установке времени ожидания битвы дивизий(%v)\n\terr=%v\n", strTime, err)
		return
	}
}

// При необходимости поднимает взвод в атаку, вызывается только если обнаружено приглашение (+)
func (сам *DivWar) upDivWar() {
	var (
		strOut      string
		lstDivWar   = сам.СписПолучить()
		еслиНайдено bool
	)
	for _, strOut = range lstDivWar {
		if strings.Contains(strOut, `>Взвод, подъем! В атаку!<`) {
			еслиНайдено = true
			break
		}
		if strings.Contains(strOut, `<div class="white medium cntr bold mb5">Вы в рядах участников</div>`) {
			// log._rintf("INFO DivWar.upDivWar(): уже зарегистрирован\n")
			return
		}
	}
	if !еслиНайдено {
		return
	}
	// Найдено приглашение на участие
	lstUp := strings.Split(strOut, `<a class="simple-but border" href="`)
	linkUp := lstUp[1]
	lstUp = strings.Split(linkUp, `"><span><span>Взвод, подъем! В атаку!</span></span></a>`)
	linkUp = "https://wartank.ru/" + lstUp[0]
	lstDivWar, err := сам.net.Get(linkUp)
	if err != nil {
		// log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
		return
	}
	if err = сам.СтрОбновить(lstDivWar); err != nil {
		log.Printf("DivWar.upDivWar(): при обновлении lstDivWar, err=\n\t%v\n", err)
	}
	// log._rintf("INFO DivWar.upDivWar(): регистрация прошла успешно\n")
}

// Ведёт сражение
func (сам *DivWar) DivWar() {
	defer func() {
		сам.divOn = nil
		сам.block.Unlock()
		if err := сам.ОбратВремяУст("01"); err != nil {
			panic(fmt.Errorf("DivWar.DivWar(): при установке CountDown, err=\n\t%w", err))
		}
		// log.Printf("INFO DivWar.DivWar(): сражение завершено\n")
	}()
	var err error
	сам.divOn, err = div_war_on.NewDivWarOn(сам.bot) // IDivWarOn (онлайн)
	if err != nil {
		// log._rintf("ERRO DivWar.DivWarOn(): при создании IDivWarOn, err=\n\t%v\n", err)
		time.Sleep(time.Millisecond * 250)
		return
	}
	// Цикл ожидания окончания сражения
	for !сам.divOn.ЕслиКонец().Получ() {
		time.Sleep(time.Second * 1)
	}

}

// Alarm -- возвращает признак начала сражения (для браузера)
func (сам *DivWar) Alarm() types.ИСтатПарам {
	return сам.alarm
}
