package mine

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"wartank/pkg/components/section"
	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/angar/base/mine/minenet"
	"wartank/server/serv_bots/warbot/tank/tankstat/static_param"
)

/*
	Объект шахты на базе
*/

// Mine -- объект шахты на базе
type Mine struct {
	*section.Section
	net        *minenet.MineNet
	server     types.IServer
	bot        types.IServBot
	base       types.IBase
	ruda       types.IStatParam
	ferrum     types.IStatParam
	steel      types.IStatParam
	plumbum    types.IStatParam
	numProduct types.IStatParam
}

// NewMine -- возвращает новый *Mine
func NewMine(server types.IServer, bot types.IServBot) (*Mine, error) {
	{ // Предусловие
		if server == nil {
			return nil, fmt.Errorf("NewMine(): IServer == nil")
		}
		if bot == nil {
			return nil, fmt.Errorf("NewMine(): IServBot == nil")
		}
	}
	sf := &Mine{
		server:     server,
		bot:        bot,
		base:       bot.Angar().Base(),
		ruda:       static_param.NewStaticParam("ruda"),
		ferrum:     static_param.NewStaticParam("ferrum"),
		steel:      static_param.NewStaticParam("steel"),
		plumbum:    static_param.NewStaticParam("plumbum"),
		numProduct: static_param.NewStaticParam("plumbum"),
	}
	return sf, nil
}

func (sf *Mine) Run() error {
	var err error
	{ // Секция
		sf.Section, err = section.NewSection(sf.server, `<span class="green2">Руда</span><br/>`)
		if err != nil {
			return fmt.Errorf("Mine.Run(): in create *Section, err=\n\t%w", err)
		}
	}

	{ // Шахта
		sf.net, err = minenet.NewMineNet(sf.server, sf.bot)
		if err != nil {
			return fmt.Errorf("Mine.Run(): in create NetMine, err=\n\t%w", err)
		}
		if err := sf.net.Run(); err != nil {
			return fmt.Errorf("Mine.Run(): in run NetMine, err=\n\t%w", err)
		}
	}
	go sf.run()
	return nil
}

// run -- запускает обработку шахты
func (sf *Mine) run() {
	sf.CountDown().Set(1)
	for {
		select {
		case <-sf.server.Done():
			sf.CountDown().Stop()
			return
		case <-sf.CountDown().ChanSig():
			log.Printf("Mine.run(): time sig")
			work := sf.ModeCurrent().Work()
			if work == "upgrade" {
				continue
			}
			if err := sf.net.UpdateLst("Шахта"); err != nil {
				log.Printf("ERRO Mine.Run(): при обновлении lstMine, err=\n\t%v\n", err)
				continue
			}
			if err := sf.selectProduct(); err != nil {
				log.Printf("ERRO MineNet.Run(): при выборе продукции, err=\n\t%v\n", err)
				continue
			}

			switch work {
			case "руда":
				sf.makeRuda()
			case "железо":
				sf.makeFerrum()
			case "сталь":
				sf.makeSteel()
			default:
				// log._rintf("ERRO MineNet.Run(): неизвестный режим производства, режим=%q\n", work)
			}
		}
		// time.Sleep(time.Second * 30)
	}
}

// Plumbum -- возвращает объект свинца
func (sf *Mine) Plumbum() types.IStatParam {
	return sf.plumbum
}

// Steel -- возвращает объект стали
func (sf *Mine) Steel() types.IStatParam {
	return sf.steel
}

// Ferrum -- возвращает объект железа
func (sf *Mine) Ferrum() types.IStatParam {
	return sf.ferrum
}

// Ruda -- возвращает объект руды
func (sf *Mine) Ruda() types.IStatParam {
	return sf.ruda
}

// NumProduct -- возвращает количество прозводимого продукта
func (sf *Mine) NumProduct() types.IStatParam {
	return sf.numProduct
}

// Выбирает продукцию по возможности произвести и её количеству
func (sf *Mine) selectProduct() error {
	var (
		mapProduct = make(map[string]bool) // Словарь известной продукции
		lstMine    = sf.GetLst()
	)

	fnProduct := func() { // вычисляет список допустимой продукции
		mapProduct["ruda"] = true // Руда есть всегда
		mapProduct["ferrum"] = false
		mapProduct["steel"] = false
		mapProduct["plumbum"] = false
		for _, strProd := range lstMine { // Проверить железо
			if strings.Contains(strProd, `<span class="green2">Железо</span><br/>`) {
				mapProduct["ferrum"] = true
				break
			}
		}
		for _, strProd := range lstMine { // Проверить сталь
			if strings.Contains(strProd, `<span class="green2">Сталь</span><br/>`) {
				mapProduct["steel"] = true
				break
			}
		}
		for _, strProd := range lstMine { // Проверить свинец
			if strings.Contains(strProd, `<span class="green2">Свинец</span><br/>`) {
				mapProduct["plumbum"] = true
				break
			}
		}
	}
	fnProduct()
	sf.ModeCurrent().WorkSet("руда")
	ruda := sf.Ruda().Get()

	ferrum := sf.Ferrum().Get()
	if mapProduct["ferrum"] {
		if ruda >= ferrum*2 {
			sf.ModeCurrent().WorkSet("железо")
		}
	}

	steel := sf.Steel().Get()
	if mapProduct["steel"] {
		if ferrum >= steel*2 {
			sf.ModeCurrent().WorkSet("сталь")
		}
	}

	plumbum := sf.Plumbum().Get()
	if mapProduct["plumbum"] {
		if steel > plumbum*2 {
			sf.ModeCurrent().WorkSet("свинец")
		}
	}

	return nil
}

// Создаёт руду
func (sf *Mine) makeRuda() {
	var (
		lstMine = sf.GetLst()
		ind     int
		strOut  string
		strTime string
		strLink string
		strNum  string
		isFind  bool
	)
	for ind, strOut = range lstMine {
		if strings.Contains(strOut, `<span class="green2">Руда</span><br/>`) {
			strNum = lstMine[ind+1]
			strTime = lstMine[ind+3]
			strLink = lstMine[ind+10]
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	if !strings.Contains(strLink, `>Начать производство<`) {
		return
	}
	lstLink := strings.Split(strLink, `<a class="simple-but border" href="`)
	strLink = lstLink[1]
	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
	strLink = "http://wartank.ru/production/" + lstLink[0]
	lstMine, err := sf.net.Get(strLink)
	if err != nil {
		// log._rintf("ERRO MineNet.makeRuda(): при GET-команде 'начать производство руды', err=\n\t%v\n", err)
		return
	}
	isFind = false
	for _, strOut = range lstMine {
		if strings.Contains(strOut, `<title>База</title>`) {
			// log._rintf("WARN MineNet.makeRuda(): при обновлении lstMine обнаружено lstBase\n")
			return
		}
	}
	if err = sf.Update(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeRuda(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.CountDown().Parse(strTime); err != nil {
		log.Printf("ERRO Mine.makeRuda(): при установке времени ожидания добычи руды(%v)\n\terr=%v\n", strTime, err)
	}
	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
	strNum = lstNum[1]
	lstNum = strings.Split(strNum, `</span><br/>`)
	strNum = lstNum[0]
	iNum, err := strconv.Atoi(strNum)
	if err != nil {
		// log._rintf("ERRO MineNet.makeRuda(): кол-во(%v) не число, err=\n\t%v\n", strNum, err)
		return
	}
	sf.NumProduct().Set(iNum)
}

// Создаёт железо
func (sf *Mine) makeFerrum() {
	var (
		lstMine = sf.GetLst()
		ind     int
		strOut  string
		strTime string
		strLink string
		strNum  string
		isFind  bool
	)
	for ind, strOut = range lstMine {
		if strings.Contains(strOut, `<span class="green2">Железо</span><br/>`) {
			strNum = lstMine[ind+1]
			strTime = lstMine[ind+3]
			strLink = lstMine[ind+10]
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	if !strings.Contains(strLink, `>Начать производство<`) {
		return
	}
	lstLink := strings.Split(strLink, `<a class="simple-but border" href="`)
	strLink = lstLink[1]
	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
	strLink = "http://wartank.ru/production/" + lstLink[0]
	lstMine, err := sf.net.Get(strLink)
	if err != nil {
		// log._rintf("ERRO MineNet.makeFerrum(): при GET-команде 'начать производство железа', err=\n\t%v\n", err)
		return
	}
	for _, strOut := range lstMine { // Проверка на базу
		if strings.Contains(strOut, `<title>База</title>`) {
			// log._rintf("ERRO MineNet.makeFerrum(): при обновлении lstMine найден lstBase")
			return
		}
	}
	if err = sf.Update(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeFerrum(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.CountDown().Parse(strTime); err != nil {
		log.Printf("ERRO Mine.makeFerrum(): при установке времени производства железа(%v)\n\terr=%v\n", strTime, err)
	}
	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
	strNum = lstNum[1]
	lstNum = strings.Split(strNum, `</span><br/>`)
	strNum = lstNum[0]
	iNum, err := strconv.Atoi(strNum)
	if err != nil {
		// log._rintf("ERRO MineNet.makeFerrum(): кол-во(%v) не число, err=\n\t%v\n", strNum, err)
		return
	}
	sf.NumProduct().Set(iNum)
}

// Создаёт сталь
func (sf *Mine) makeSteel() {
	var (
		lstMine = sf.GetLst()
		ind     int
		strOut  string
		strTime string
		strLink string
		strNum  string
		isFind  bool
	)
	for ind, strOut = range lstMine {
		if strings.Contains(strOut, `<span class="green2">Сталь</span><br/>`) {
			strNum = lstMine[ind+1]
			strTime = lstMine[ind+3]
			strLink = lstMine[ind+10]
			isFind = true
			break
		}
	}
	if !isFind {
		return
	}
	if !strings.Contains(strLink, `>Начать производство<`) {
		return
	}
	lstLink := strings.Split(strLink, `<a class="simple-but border" href="`)
	strLink = lstLink[1]
	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
	strLink = "http://wartank.ru/production/" + lstLink[0]
	lstMine, err := sf.net.Get(strLink)
	if err != nil {
		// log._rintf("ERRO MineNet.makeSteel(): при GET-команде 'начать производство стали', err=\n\t%v\n", err)
		return
	}
	for _, strOut := range lstMine { // Проверка на базу
		if strings.Contains(strOut, `<title>База</title>`) {
			// log._rintf("ERRO MineNet.makeSteel(): при обновлении lstMine найден lstBase")
			return
		}
	}
	if err = sf.Update(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeSteel(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.CountDown().Parse(strTime); err != nil {
		log.Printf("ERRO Mine.makeSteel(): при установке времени производства железа(%v)\n\terr=%v\n", strTime, err)
	}
	lstNum := strings.Split(strNum, `Кол-во: <span class="green2">`)
	strNum = lstNum[1]
	lstNum = strings.Split(strNum, `</span><br/>`)
	strNum = lstNum[0]
	iNum, err := strconv.Atoi(strNum)
	if err != nil {
		// log._rintf("ERRO MineNet.makeSteel(): кол-во(%v) не число, err=\n\t%v\n", strNum, err)
		return
	}
	sf.NumProduct().Set(iNum)
}
