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"
)

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

// Шахта -- объект шахты на базе
type Шахта struct {
	*section.Section
	net        *minenet.MineNet
	бот        types.ИБот
	база       types.ИБаза
	руда       types.ИСтатПарам
	железо     types.ИСтатПарам
	сталь      types.ИСтатПарам
	свинец     types.ИСтатПарам
	numProduct types.ИСтатПарам
}

// НовШахта -- возвращает новый *Mine
func НовШахта(база types.ИБаза) (*Шахта, error) {
	section, err := section.NewSection(база.Бот(), "Шахта", `<span class="green2">Руда</span><br/>`)
	if err != nil {
		return nil, fmt.Errorf("НовШахта(): in create *Section, err=\n\t%w", err)
	}
	руда, ош := static_param.НовСтатПарам("ruda")
	if ош != nil {
		return nil, fmt.Errorf("НовШахта(): при создании статистики руды, ош=\n\t%w", ош)
	}
	железо, ош := static_param.НовСтатПарам("ferrum")
	if ош != nil {
		return nil, fmt.Errorf("НовШахта(): при создании статистики железа, ош=\n\t%w", ош)
	}
	сталь, ош := static_param.НовСтатПарам("steel")
	if ош != nil {
		return nil, fmt.Errorf("НовШахта(): при создании статистики стали, ош=\n\t%w", ош)
	}
	свинец, ош := static_param.НовСтатПарам("plumbum")
	if ош != nil {
		return nil, fmt.Errorf("НовШахта(): при создании статистики свинца, ош=\n\t%w", ош)
	}
	добычаЧисло, ош := static_param.НовСтатПарам("plumbum")
	if ош != nil {
		return nil, fmt.Errorf("НовШахта(): при создании статистики числа добычи, ош=\n\t%w", ош)
	}
	sf := &Шахта{
		Section:    section,
		бот:        база.Бот(),
		база:       база,
		руда:       руда,
		железо:     железо,
		сталь:      сталь,
		свинец:     свинец,
		numProduct: добычаЧисло,
	}
	sf.net, err = minenet.NewMineNet(sf)
	if err != nil {
		return nil, fmt.Errorf("NewMine(): in create NetMine, err=\n\t%w", err)
	}
	return sf, nil
}

func (sf *Шахта) Run() error {
	go sf.run()
	return nil
}

// run -- запускает обработку шахты
func (sf *Шахта) run() {
	sf.SetCountDown(1)
	for {
		select {
		case <-sf.бот.Кнт().Done():
			sf.ВремяОпрос().Стоп()
			return
		case <-sf.ВремяОпрос().КаналСиг():
			log.Printf("Mine.run(): time sig")
			sf.Section.SetCountDown(120)
			work := sf.РежимТекущ().Режим()
			log.Printf("Mine.run(): work=%v\n", 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)
	}
}

// Свинец -- возвращает объект свинца
func (sf *Шахта) Свинец() types.ИСтатПарам {
	return sf.свинец
}

// Сталь -- возвращает объект стали
func (sf *Шахта) Сталь() types.ИСтатПарам {
	return sf.сталь
}

// Железо -- возвращает объект железа
func (sf *Шахта) Железо() types.ИСтатПарам {
	return sf.железо
}

// Руда -- возвращает объект руды
func (sf *Шахта) Руда() types.ИСтатПарам {
	return sf.руда
}

// КолвоСделатьСейчас -- возвращает количество прозводимого продукта
func (sf *Шахта) КолвоСделатьСейчас() types.ИСтатПарам {
	return sf.numProduct
}

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

	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.РежимТекущ().РежимУст("руда")
	ruda := sf.Руда().Получ()

	ferrum := sf.Железо().Получ()
	if mapProduct["ferrum"] {
		if ruda >= ferrum*2 {
			sf.РежимТекущ().РежимУст("железо")
		}
	}

	steel := sf.Сталь().Получ()
	if mapProduct["steel"] {
		if ferrum >= steel*2 {
			sf.РежимТекущ().РежимУст("сталь")
		}
	}

	plumbum := sf.Свинец().Получ()
	if mapProduct["plumbum"] {
		if steel > plumbum*2 {
			sf.РежимТекущ().РежимУст("свинец")
		}
	}

	return nil
}

// Создаёт руду
func (sf *Шахта) makeRuda() {
	var (
		lstMine = sf.СписПолучить()
		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.СтрОбновить(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeRuda(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.ParseCountDown(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.КолвоСделатьСейчас().Уст(iNum)
}

// Создаёт железо
func (sf *Шахта) makeFerrum() {
	var (
		lstMine = sf.СписПолучить()
		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.СтрОбновить(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeFerrum(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.ParseCountDown(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.КолвоСделатьСейчас().Уст(iNum)
}

// Создаёт сталь
func (sf *Шахта) makeSteel() {
	var (
		lstMine = sf.СписПолучить()
		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.СтрОбновить(lstMine); err != nil {
		// log._rintf("ERRO MineNet.makeSteel(): при обновлении lstMine, err=\n\t%v\n", err)
		return
	}
	if err := sf.ParseCountDown(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.КолвоСделатьСейчас().Уст(iNum)
}
