package health

import (
	"context"
	"fmt"
	// "log"
	// "strconv"
	"strings"
	"time"
	"wartank/server/serv_bots/warbot/angar/division/div_war/div_war_on/health/health_time"
	"wartank/server/serv_bots/warbot/angar/division/div_war/div_war_on/health/repair_time"
	// "wartank/internal/components/sound"
	"wartank/pkg/components/safe_bool"
	"wartank/pkg/types"
)

/*
	Контролирует состояние здоровья танка
*/

// Health -- контроль здоровья танка
type Health struct {
	types.ИДивизияВойнаДействие // FIXME:
	fnCancel                    func()
	temp                        *health_time.HealthTime // Изменяемое здоровье танка
	full                        *health_time.HealthTime // Полное здоровье танка
	isRepair                    *safe_bool.БезопБул     // Необходимость восстановления
	repairTime                  *repair_time.RepairTime // Время до восстановления
	isEnd                       *safe_bool.БезопБул     // Ссылка на признак конца сражения
	login                       string                  // Для поиска контрольных строк
	chTick                      chan int                // Канал для ровной отправки тиков
	// deltaOld                    int                    // Старая дельта потери здоровья
	// countLow                    int
	ctxBattle context.Context // Контекст сражения
}

// NewHealth -- возвращает новый *Health
func NewHealth(дивВойна types.ИДивизияВойнаДействие, isEnd *safe_bool.БезопБул, login string) (*Health, error) {
	{ // Предусловия
		if дивВойна == nil {
			return nil, fmt.Errorf("NewHealth(): дивВойна is nil")
		}
		if isEnd == nil {
			return nil, fmt.Errorf("NewHealth(): isEnd is nil")
		}
		if login == "" {
			return nil, fmt.Errorf("NewHealth(): login is empty")
		}
	}
	сам := &Health{
		ИДивизияВойнаДействие: дивВойна,
		fnCancel:   дивВойна.CancelBattle,
		ctxBattle:  дивВойна.Ctx(),
		temp:       health_time.NewHealthTime(),
		full:       health_time.NewHealthTime(),
		isRepair:   safe_bool.НовБезопБул(),
		repairTime: repair_time.NewRepairTime(),
		isEnd:      дивВойна.ЕслиКонец(),
		login:      login,
		chTick:     make(chan int, 2),
	}
	go сам.makeTik()
	go сам.run()
	return сам, nil
}

// Отправляет тики с заданным равным интервалом
func (сам *Health) makeTik() {
	defer func() {
		сам.CancelBattle()
		close(сам.chTick)
		// log._rintf("Health.makeTick(): сражение завершёно\n")
	}()
	count := 0
	repairTime := 0
	for {
		select {
		case <-сам.ctxBattle.Done():
			return
		default:
			if сам.IsDeath() {
				return
			}
			if сам.repairTime.Get() == repairTime {
				count++
			} else {
				repairTime = сам.repairTime.Get()
				count = 0
			}
			if count > 90 {
				return
			}
		}
		сам.chTick <- 1
		time.Sleep(time.Second * 1)
		сам.repairTime.Dec()
	}
}

// Главный цикл обработки здоровья в сражении
func (сам *Health) run() {
	for {
		select {
		case <-сам.ctxBattle.Done():
			сам.isEnd.Уст()
			return
		case <-сам.chTick:
			// if err := сам.findHealth(); err != nil { // Найти свой здоровье
			// 	// log._rintf("ERRO Health.run(): при попытке найти здоровье, err=\n\t%v\n", err)
			// }
			сам.findRepairTime()
			if сам.ВыстрелБлок().Получ() {
				if сам.isRepair.Получ() {
					go сам.repair()
				}
				continue
			}
			if сам.isRepair.Получ() {
				go сам.repair()
			}
		}
	}
}

// Full -- возвращает объект полного здоровья танка
func (сам *Health) Full() int {
	return сам.full.Get()
}

// IsDeath -- возвращает признак мертвичины танка
func (сам *Health) IsDeath() bool {
	if сам.isEnd.Получ() {
		сам.fnCancel()
		return true
	}
	lstBattle := сам.СписПолучить()
	for _, strOut := range lstBattle {
		if strings.Contains(strOut, `>Ваш танк подбит.`) {
			// log._rintf("INFO Health.repair(): танк подбит\n")
			сам.temp.Set(0)
			сам.isEnd.Уст()
			сам.CancelBattle()
			return true
		}
	}
	return сам.isEnd.Получ()
}

// Ищет время восстановления ремки
func (сам *Health) findRepairTime() {
	defer func() {
		if сам.repairTime.IsReady() {
			return
		}
		// if сам.repairTime.IsChange() {
		// log._rintf("INFO Health.findRepair(): до ремки=%v\n", сам.repairTime.Get())
		// }
	}()
	if сам.repairTime.IsReady() {
		return
	}
	var (
		strOut      string
		lstBattle   = сам.СписПолучить()
		еслиНайдено bool
		ind         int
	)
	// <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
	//
	for ind, strOut = range lstBattle {
		if !strings.Contains(strOut, `ILinkListener-currentControl-repairLink`) {
			continue
		}
		if strings.Contains(strOut, ` секунд</span></span></a>`) {
			еслиНайдено = true
			break
		}
	}
	if !еслиНайдено {
		return
	}
	strOut = lstBattle[ind]
	// <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
	lstTime := strings.Split(strOut, `ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>`)
	if len(lstTime) < 2 {
		// log._rintf("ERRO Health.findRepair(): при попытке получить ссылку на ремонт, strOut=\n%v\n", strOut)
		сам.isEnd.Уст()
		сам.CancelBattle()
		return
	}
	// strTime := lstTime[1]
	// lstTime = strings.Split(strTime, ` секунд</span></span></a>`)
	// strTime = lstTime[0]
	// if err := сам.repairTime.Set(strTime); err != nil {
	// 	 log._rintf("ERRO Health.findRepair(): при установке времени восстановления ремки, err=\n\t%v\n", err)
	// }
}

// Восстанавливает здоровье (~)
func (сам *Health) repair() {
	var (
		strOut            string
		lstBattleOn       = сам.СписПолучить()
		еслиНайденоRepair bool
		ind               int
	)
	// <span>Ремкомплект</span>
	// <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
	for ind, strOut = range lstBattleOn {
		if strings.Contains(strOut, `<span>Ремкомплект</span>`) {
			еслиНайденоRepair = true
			break
		}
	}
	if !еслиНайденоRepair {
		return
	}
	strOut = lstBattleOn[ind]
	// <a href="pve?6-26.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
	lstLink := strings.Split(strOut, `<a href="`)
	strLink := lstLink[1]
	lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Ремкомплект</span></span></a>`)
	strLink = "https://wartank.ru/" + lstLink[0]
	lstBattleOn, err := сам.Сеть().Get(strLink)
	if err != nil {
		// log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err)
		сам.isEnd.Уст()
		сам.CancelBattle()
		return
	}
	if err = сам.СтрОбновить(lstBattleOn); err != nil {
		// log._rintf("ERRO Health.repair(): при обновлении lstBattle, err=\n\t%v\n", err)
		сам.isEnd.Уст()
		сам.CancelBattle()
		return
	}
	// sound.Repair()
	// log._rintf("INFO Health.repair(): здоровье восстановлено\n")
}

// Ищет своё здоровье (~)
// func (сам *Health) findHealth() error {
// 	var (
// 		ind         int
// 		strOut      string
// 		еслиНайдено bool
// 		lstBattle   = сам.СписПолучить()
// 	)
// 	if len(lstBattle) == 0 { // Принудительно обновим сражение
// 		if err := сам.Сеть().Обновить(); err != nil {
// 			сам.isEnd.Уст()
// 			сам.fnCancel()
// 			return fmt.Errorf("Health.findHealth(): после принудительного обновления lsBattleOn, err=\n\t%w", err)
// 		}
// 	}
// 	for ind, strOut = range lstBattle {
// 		if strings.Contains(strOut, `alt="`+сам.login+`"`) {
// 			еслиНайдено = true
// 			break
// 		}
// 	}
// 	if !еслиНайдено { // Свой танк не найден
// 		сам.isEnd.Уст()
// 		сам.fnCancel()
// 		return fmt.Errorf("Health.findHealth(): своё здоровье не найдено")
// 	}
// 	// Свой танк найден, ищем здоровье
// 	ind += 11
// 	strOut = lstBattle[ind]
// 	lstHealth := strings.Split(strOut, `<div class="value-block lh1"><span><span>`)
// 	strHealth := lstHealth[1]
// 	lstHealth = strings.Split(strHealth, `</span></span></div>`)
// 	strHealth = lstHealth[0]
// 	iHealth, err := strconv.Atoi(strHealth)
// 	if err != nil {
// 		сам.isEnd.Уст()
// 		сам.CancelBattle()
// 		return fmt.Errorf("Health.findHealth(): здоровье(%v) не число, err=%w", strHealth, err)
// 	}
// 	сам.setHealth(iHealth)
// 	return nil
// }

// setHealth -- устанавливает текущее здоровье
// func (сам *Health) setHealth(val int) {
// 	if val < 0 {
// 		// log._rintf("WARN Health.setHealth(): кривое значение здоровья танка(%v)\n", val)
// 		val = 0
// 	}

// 	if val > сам.full.Get() {
// 		// log._rintf("WARN Health.setHealth(): кривое текущее здоровье, %v/%v\n", val, сам.full.Get())
// 		сам.full.Set(val)
// 		сам.temp.Set(val)
// 		// сам.deltaOld = 0
// 		сам.ВыстрелБлок().Сброс()
// 		сам.isRepair.Сброс()
// 		return
// 	}

// 	delta := сам.temp.Get() - val
// 	// if delta > 0 { // Дельта будет больше нуля, если только
// 	// 	if delta != сам.deltaOld {
// 	// 		// log._rintf("INFO Health.setHealth(): потеря здоровья=%v/%v\n", -delta, val)
// 	// 		сам.deltaOld = delta
// 	// 		сам.temp.Set(val)
// 	// 	}
// 	// }

// 	switch {
// 	case сам.isEnd.Получ():
// 		сам.temp.Set(0)
// 		сам.isEnd.Уст()
// 		сам.CancelBattle()
// 		return
// 	case val == 0:
// 		сам.temp.Set(0)
// 		сам.isEnd.Уст()
// 		сам.CancelBattle()
// 		return
// 	case val <= 500: // Запретить стрельбу
// 		сам.ВыстрелБлок().Уст() // Установить запрет стрельбы пока слабое здоровье
// 		сам.isRepair.Уст()
// 		// log._rintf("WARN Health.setHealth(): низкий уровень здоровья(%v)\n", val)
// 		сам.Манёвр()
// 	case val > 500: // Разрешить стрельбы
// 		сам.ВыстрелБлок().Сброс()
// 		сам.isRepair.Сброс()
// 		if delta > сам.full.Get()*4/10 { // Проверить на критичность падения здоровья на 40%
// 			// log._rintf("WARN Health.setHealth(): большая разовая потеря здоровья(%v)\n", delta)
// 			сам.Манёвр()
// 			сам.isRepair.Уст()
// 			return
// 		}
// 	}

// 	isMask := сам.ВыстрелБлок().Получ()
// 	switch isMask {
// 	case true:
// 		// сам.countLow++
// 		// if сам.countLow >= 200 {
// 		// 	сам.isEnd.Уст()
// 		// 	сам.CancelBattle()
// 		// 	return
// 		// }
// 	default:
// 		// сам.countLow = 0
// 	}
// 	if val == сам.full.Get() {
// 		сам.temp.Set(val)
// 		сам.isRepair.Сброс()
// 		сам.ВыстрелБлок().Сброс()
// 		// сам.countLow = 0
// 	}
// }
