package angar

import (
	"fmt"
	"sync"

	// "log"
	"strconv"
	"strings"

	"wartank/pkg/components/section"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/angar_attack"
	"wartank/server/serv_bots/warbot/angar/angarnet"
	"wartank/server/serv_bots/warbot/angar/base"
	"wartank/server/serv_bots/warbot/angar/batmas"
	"wartank/server/serv_bots/warbot/angar/battle"
	"wartank/server/serv_bots/warbot/angar/convoy"
	"wartank/server/serv_bots/warbot/angar/fuel"
	"wartank/server/serv_bots/warbot/angar/missions"
	"wartank/server/serv_bots/warbot/angar/netstat"
	"wartank/server/serv_bots/warbot/tank/tankstat/static_param"
)

/*
	Объект ангара приложения
*/

// Angar -- ангар для танка
type Angar struct {
	*section.Section
	net     *angarnet.AngarNet
	netKill *angar_attack.AngarAttack

	server types.IServer
	bot    types.IServBot
	convoy *convoy.Convoy
	battle *battle.Battle
	batMas *batmas.BatMas
	base   *base.Base
	award  *missions.Missions

	gold     types.IStatParam
	level    types.IStatParam
	progress types.IStatParam
	fuel     *fuel.Fuel
	online   types.IStatParam

	silverAll    types.IStatParam
	silverOnline types.IStatParam

	stat  *netstat.NetStat
	block sync.Mutex
}

// NewAngar -- возвращает новый *Angar
func NewAngar(server types.IServer, bot types.IServBot) (*Angar, error) {
	{ // Предусловия
		if server == nil {
			return nil, fmt.Errorf("NewAngar(): IServer == nil")
		}
		if bot == nil {
			return nil, fmt.Errorf("NewAngar(): IServBot == nil")
		}
	}

	sf := &Angar{
		server:   server,
		bot:      bot,
		gold:     static_param.NewStaticParam("gold"),
		level:    static_param.NewStaticParam("level"),
		progress: static_param.NewStaticParam("progress"),
		online:   static_param.NewStaticParam("online"),

		silverAll:    static_param.NewStaticParam("silver_all"),
		silverOnline: static_param.NewStaticParam("silver_online"),
	}
	return sf, nil
}

// Одноразовый вызов для создания компонентов при запуске в работу
func (sf *Angar) make() error {
	sf.block.Lock()
	defer sf.block.Unlock()
	var err error
	{ // Section
		sf.Section, err = section.NewSection(sf.server, `<title>Ангар</title>`)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create *Section, err=\n\t%w", err)
		}
	}
	{ // Сеть
		sf.net, err = angarnet.NewAngarNet(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create <AngarNet>, err=\n\t%w", err)
		}
	}
	{ // Сеть атаки
		sf.netKill, err = angar_attack.NewAngarAttack(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create <AngarAttackNet>, err=\n\t%w", err)
		}
	}
	{ // Статистика
		sf.stat, err = netstat.NewNetStat(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create NetResource, err=\n\t%w", err)
		}
	}
	{ // Convoy
		sf.convoy, err = convoy.NewConvoy(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create IConvoy, err=\n\t%w", err)
		}
	}
	{ // Сражение
		sf.battle, err = battle.NewBattle(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create IBattle, err=\n\t%w", err)
		}
	}
	{ // Битва мастеров
		sf.batMas, err = batmas.NewBatMas(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in create *BatMas, err=\n\t%w", err)
		}
		// go sf.batMas.Run()
	}
	{ // База
		sf.base, err = base.NewBase(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in make IBase, err=\n\t%w", err)
		}
	}
	{ // Миссии
		sf.award, err = missions.NewMissions(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in make *Missions, err=\n\t%w", err)
		}
	}
	{ // Топливо
		sf.fuel, err = fuel.NewFuel(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Angar.make(): in make *Missions, err=\n\t%w", err)
		}
	}
	return nil
}

// запускает обработку ангара
func (sf *Angar) Run() error {
	{ // Запуск компонентов
		err := sf.make()
		if err != nil {
			return fmt.Errorf("Angar.Run(): при создании компонентов ангара, err=\n\t%w", err)
		}
		if err := sf.net.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске сетевой секции ангара, err=\n\t%w", err)
		}
		if err := sf.netKill.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске сетевой секции опыт за топливо, err=\n\t%w", err)
		}
		if err := sf.convoy.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске конвоя, err=\n\t%w", err)
		}
		if err := sf.battle.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске сражения, err=\n\t%w", err)
		}
		if err := sf.batMas.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске схватки, err=\n\t%w", err)
		}
		if err := sf.base.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске базы, err=\n\t%w", err)
		}
		if err := sf.award.Run(); err != nil {
			return fmt.Errorf("Angar.Run(): при пуске наград, err=\n\t%w", err)
		}
		go sf.fuel.Run()
	}

	go func() {
		sf.CountDown().Set(1)
		count := 0
		for {
			select {
			case <-sf.server.Done(): // Отмена контекста
				sf.CountDown().Stop()
				return
			case <-sf.CountDown().ChanSig(): // Метка времени
				sf.updateResurs()
				sf.stat.Update()
				switch count {
				case 0:
					sf.checkConvoy()
					count = 6
				default:
					count--
				}
				sf.CountDown().Set(60)
			}
		}
	}()
	return nil
}

// Обновляет ресурсы ангара
func (sf *Angar) updateResurs() {
	if err := sf.net.UpdateLst("ангар"); err != nil {
		// log._rintf("ERRO Angar.updateResurs(): при обработке ангара в сети, err=\n\t%v\n", err)
		return
	}
	sf.findGold()
	sf.findSilver()
}

// IMissions -- возвращает ссылку на объект миссий
func (sf *Angar) Missions() types.IMissions {
	return sf.award
}

// Battle -- возвращает объект сражения
func (sf *Angar) Battle() types.IBattle {
	return sf.battle
}

// Convoy -- возвращает объект конвоя
func (sf *Angar) Convoy() types.IConvoy {
	return sf.convoy
}

// Gold -- возвращает объект золота
func (sf *Angar) Gold() types.IStatParam {
	return sf.gold
}

// Fuel -- возвращает объект топлива
func (sf *Angar) Fuel() types.IStatParam {
	return sf.fuel.Fuel()
}

// Level -- возвращает объект уровня игрока
func (sf *Angar) Level() types.IStatParam {
	return sf.level
}

// Progress -- возвращает прогрес уровня игрока
func (sf *Angar) Progress() types.IStatParam {
	return sf.progress
}

// Online -- возвращает количество игроков онлайн
func (sf *Angar) Online() types.IStatParam {
	return sf.online
}

// SilverAll -- возвращает объект всего серебра в ангаре
func (sf *Angar) SilverAll() types.IStatParam {
	return sf.silverAll
}

// SilverOnline -- возвращает объект серебра за сессию в ангаре
func (sf *Angar) SilverOnline() types.IStatParam {
	return sf.silverOnline
}

// SilverUpdate -- на основе фактического серебра -- обновляет вырабатанное серебро
func (sf *Angar) SilverUpdate(silverFact int) {
	if sf.silverAll.Get() == 0 { // Если запуск
		sf.silverAll.Set(silverFact)
		return
	}
	if sf.silverAll.Get() > silverFact { // Если потрачего серебро
		sf.silverAll.Set(silverFact)
		return
	}
	if sf.silverAll.Get() < silverFact { // Если заработано
		so := sf.silverOnline.Get()
		sd := silverFact - sf.silverAll.Get()
		sf.silverOnline.Set(so + sd)
	}
	sf.silverAll.Set(silverFact)
}

// Base -- возвращает базу
func (sf *Angar) Base() types.IBase {
	sf.block.Lock()
	defer sf.block.Unlock()
	return sf.base
}

// Проверяет на исполнение конвоя
func (sf *Angar) checkConvoy() {
	var (
		strOut   string
		isFind   bool
		lstAngar = sf.GetLst()
	)
	for _, strOut = range lstAngar {
		if strings.Contains(strOut, `>Конвой</span>`) {
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	if !strings.Contains(strOut, `<a class="simple-but border gray mb1" href="convoy"><span><span>Конвой</span></span></a>`) {
		return
	}
	sf.convoy.UpdateLst()
}

// Ищет в теле текста ангара серебро
func (sf *Angar) findSilver() {
	// _mt.Println("\tAngarNet.findSilver()")
	lstAngar := sf.GetLst()
	var strOut string
	for _, strSilver := range lstAngar {
		if strings.Contains(strSilver, `<img title="Серебро" `) {
			strOut = strSilver
			break
		}
	}
	// Выделить топливо
	lstSilver := strings.Split(strOut, `<img title="Серебро" alt="Серебро" src="/images/icons/silver.png?2"/> `)
	strSilver := lstSilver[1]
	iSilver, err := strconv.Atoi(strSilver)
	if err != nil {
		// log._rintf("ERRO AngarNet.findSilver(): silver(%v) not number, err=\n\t%v\n", strSilver, err)
		return
	}
	sf.silverAll.Set(iSilver)
}

// Ищет в теле текста ангара золото
func (sf *Angar) findGold() {
	var (
		lstAngar = sf.bot.Angar().GetLst()
		strOut   string
		isFind   bool
	)

	for _, strGold := range lstAngar {
		if strings.Contains(strGold, `<img title="Золото" `) {
			strOut = strGold
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	// Выделить топливо
	lstGold := strings.Split(strOut, `<img title="Золото" alt="Золото" src="/images/icons/gold.png?2"/> `)
	strGold := lstGold[1]
	iGold, err := strconv.Atoi(strGold)
	if err != nil {
		// log._rintf("ERRO AngarNet.findGold(): gold(%v) not number, err=\n\t%v\n", strGold, err)
		return
	}
	sf.bot.Angar().Gold().Set(iGold)
}
