// package serv_web -- веб-сервер для графики
package serv_web

import (
	"fmt"
	"os"
	"time"
	"wartank/pkg/alias"
	"wartank/pkg/components/kernel/logger"
	"wartank/pkg/types"
	"wartank/server/serv_web/web_api"
	"wartank/server/serv_web/web_gui"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/compress"
	"github.com/gofiber/template/html/v2"
)

type СервВеб struct {
	серв   types.ИСервер
	файбер fiber.App
	порт   string
	лог    *logger.Логгер
}

// НовСервВеб -- возвращает новый веб-сервер
func НовСервВеб(серв types.ИСервер) *СервВеб {
	лог := logger.НовЛоггер("СервВеб")
	лог.Инфо("НовСервВеб()\n")
	лог.Паника(серв == nil, "НовСервВеб(): ИСервер==nil")
	рендер := html.New("./web/tmpl", ".tmpl.html")

	конф := fiber.Config{
		// Prefork:                      false,
		ServerHeader: "WarTank",
		//StrictRouting:                false,
		//CaseSensitive:                false,
		//Immutable:                    false,
		//UnescapePath:                 false,
		//ETag:                         false,
		BodyLimit: 100_000_000,
		// Concurrency: 100,
		Views: рендер,
		//ViewsLayout:                  "",
		//PassLocalsToViews:            false,
		// ReadTimeout:     15 * time.Second,
		// WriteTimeout:    15 * time.Second,
		// IdleTimeout:     15 * time.Second,
		ReadBufferSize:  4_000_000,
		WriteBufferSize: 4_000_000,
		//CompressedFileSuffix:         "",
		//ProxyHeader:                  "",
		//GETOnly:                      false,
		//ErrorHandler:                 func(*fiber.Ctx, error) error { panic("not implemented") },
		//DisableKeepalive:             false,
		//DisableDefaultDate:           false,
		//DisableDefaultContentType:    false,
		//DisableHeaderNormalizing:     false,
		//DisableStartupMessage:        false,
		AppName: "WarTank.App",
		// StreamRequestBody:            false,
		// DisablePreParseMultipartForm: false,
		// ReduceMemoryUsage:            false,
		// JSONEncoder:                  func(interface{}) ([]byte, error) { panic("not implemented") },
		// JSONDecoder:                  func([]byte, interface{}) error { panic("not implemented") },
		// XMLEncoder:                   func(interface{}) ([]byte, error) { panic("not implemented") },
		Network: "tcp4",
		// EnableTrustedProxyCheck:      false,
		// TrustedProxies:               []string{},
		// EnableIPValidation:           false,
		// EnablePrintRoutes:            false,
		// ColorScheme: fiber.Colors{
		// 	Black:   "",
		// 	Red:     "",
		// 	Green:   "",
		// 	Yellow:  "",
		// 	Blue:    "",
		// 	Magenta: "",
		// 	Cyan:    "",
		// 	White:   "",
		// 	Reset:   "",
		// },
		// RequestMethods:           []string{},
		// EnableSplittingOnParsers: false,
	}
	сам := &СервВеб{
		серв:   серв,
		файбер: *fiber.New(конф),
		лог:    лог,
	}
	компресКонфиг := compress.Config{
		Level: compress.LevelBestCompression,
	}
	сам.файбер.Use(compress.New(компресКонфиг))
	сам.файбер.Static("/static", "./web/static", fiber.Static{
		Compress:      true,
		ByteRange:     true,
		Browse:        true,
		Index:         "index.html",
		CacheDuration: 30 * time.Second,
		MaxAge:        3600,
	})

	сам.файбер.Get("/list_bot/get", сам.гетСписБот)
	сам.файбер.Post("/list_bot/add", сам.постБотНов)
	сам.файбер.Post("/bot/stat", сам.постБотСтат)
	_ = web_api.НовВебАпи(сам)
	_ = web_gui.НовВебГуи(сам)
	return сам
}

// Файбер -- возвращает файбер
func (сам *СервВеб) Файбер() *fiber.App {
	return &сам.файбер
}

// Сервер -- возвращает сервер
func (сам *СервВеб) Сервер() types.ИСервер {
	return сам.серв
}

// Пуск -- запускает веб-сервер в работу
func (сам *СервВеб) Пуск() {
	фнПуск := func() {
		сам.лог.Инфо("СервВеб.Пуск().фнПуск(): порт=%q\n", сам.порт)
		ош := сам.файбер.Listen(":" + сам.порт)
		сам.лог.Паника(ош != nil, "СервВеб.Пуск(): при работе веб-сервера, ош=\n\t%v\n", ош)
	}
	stage := os.Getenv("STAGE")
	switch stage {
	case "local":
		сам.порт = "18061"
	case "prod":
		сам.порт = "18060"
	case "prod2":
		сам.порт = "18062"
	default:
		сам.лог.Паника(true, "СервВеб.Пуск(): не установлена переменная STAGE")
	}
	go фнПуск()
}

type ПостБотСтат struct {
	Номер alias.БотНомер `form:"bot_number"`
}

// постБотСтат -- возвращает статистику бота
func (сам *СервВеб) постБотСтат(кнт *fiber.Ctx) error {
	ботСт := &ПостБотСтат{}

	if err := кнт.BodyParser(ботСт); err != nil {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотСтат(): при парсинге тела запроса, ош=\n\t%" + err.Error(),
		})
	}
	номер := ботСт.Номер
	ботоФерма := сам.серв.ServBots()
	бот := ботоФерма.Get(номер)
	if бот == nil {
		return кнт.JSON(fiber.Map{
			"error": fmt.Sprintf("СервВеб.постБотСтат(): бот c именем %q не существует", номер),
		})
	}
	диктБот := map[string]string{}
	диктБот["isAuto"] = fmt.Sprint(бот.АвтоИграЕсли())
	диктБот["isWork"] = fmt.Sprint(бот.ЕслиПуск())
	топливо := бот.Ангар().Топливо().Получ()
	if топливо == 0 {
		бот.Ангар().Обновить()
		топливо = бот.Ангар().Топливо().Получ()
	}
	диктБот["топливо"] = fmt.Sprint(топливо)
	диктБот["золото"] = fmt.Sprint(бот.Ангар().Золото().Получ())
	диктБот["серебро"] = fmt.Sprint(бот.Ангар().СереброВсего().Получ())
	слава := бот.Ангар().Конвой().Слава().Получ()
	if слава == 0 {
		бот.Ангар().Обновить()
		слава = бот.Ангар().Конвой().Слава().Получ()
	}
	диктБот["слава"] = fmt.Sprint(слава)
	диктБот["прогресс"] = fmt.Sprintf("%v%%", бот.Ангар().Прогресс().Получ())
	диктБот["уровень"] = fmt.Sprintf("%v", бот.Ангар().Уровень().Получ())
	диктБот["атака"] = fmt.Sprintf("%v", бот.Стата().Атака().Получ())
	диктБот["броня"] = fmt.Sprintf("%v", бот.Стата().Броня().Получ())
	диктБот["точность"] = fmt.Sprintf("%v", бот.Стата().Точность().Получ())
	диктБот["прочность"] = fmt.Sprintf("%v", бот.Стата().Прочность().Получ())
	диктБот["мощь"] = fmt.Sprintf("%v", бот.Стата().Мощь().Получ())

	диктБот["шахта_уровень"] = fmt.Sprintf("%v", бот.Ангар().База().Шахта().Уровень().Получ())
	диктБот["шахта_режим"] = fmt.Sprintf("%v", бот.Ангар().База().Шахта().АренаСостояние().Состояние())
	диктБот["шахта_сделать_кол"] = fmt.Sprintf("%v", бот.Ангар().База().Шахта().ПродуктКолСейчас())
	диктБот["шахта_сделать_назв"] = бот.Ангар().База().Шахта().ПродуктИмяСейчас()
	диктБот["шахта_сделать_время"] = бот.Ангар().База().Шахта().ПродуктВремяСейчас()

	диктБот["полигон_уровень"] = fmt.Sprintf("%v", бот.Ангар().База().Полигон().Уровень().Получ())
	диктБот["полигон_режим"] = fmt.Sprintf("%v", бот.Ангар().База().Полигон().АренаСостояние().Состояние())
	диктБот["полигон_сделать_кол"] = fmt.Sprintf("%v", бот.Ангар().База().Полигон().ПродуктКолСейчас())
	диктБот["полигон_сделать_назв"] = бот.Ангар().База().Полигон().ПродуктИмяСейчас()
	диктБот["полигон_сделать_время"] = бот.Ангар().База().Полигон().ПродуктВремяСейчас()
	return кнт.JSON(диктБот)
}

type ПостБотНов struct {
	Логин    string `form:"login"`
	Пароль   string `form:"pass"`
	ЕслиАвто string `form:"is_auto"`
}

// постБотНов -- добавляет бота на бото-ферму
func (сам *СервВеб) постБотНов(кнт *fiber.Ctx) error {
	бот := &ПостБотНов{}

	if err := кнт.BodyParser(бот); err != nil {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотНов(): при парсинге тела запроса, ош=\n\t%" + err.Error(),
		})
	}
	if бот.Логин == "" {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотНов(): пустой логин",
		})
	}
	if бот.Пароль == "" {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотНов(): пустой пароль",
		})
	}
	if бот.ЕслиАвто == "" {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотНов(): пустой еслиАвто",
		})
	}
	var еслиАвто bool
	if бот.ЕслиАвто == "true" {
		еслиАвто = true
	}
	ботоФерма := сам.серв.ServBots()
	ош := ботоФерма.НовБот(бот.Логин, бот.Пароль, еслиАвто)
	if ош != nil {
		return кнт.JSON(fiber.Map{
			"error": "СервВеб.постБотНов(): при создании бота %q, ош=\n\t%" + ош.Error(),
		})
	}
	return nil
}

// гетСписБот -- возвращает список ботов
func (сам *СервВеб) гетСписБот(кнт *fiber.Ctx) error {
	списБот := сам.серв.ServBots().ListBot()
	рез := make([]map[string]string, 0)
	for _, бот := range списБот {
		_бот := map[string]string{}
		_бот["name"] = бот.Имя()
		_бот["isAuto"] = fmt.Sprint(бот.АвтоИграЕсли())
		_бот["isWork"] = fmt.Sprint(бот.ЕслиПуск())
		_бот["gold"] = fmt.Sprint(бот.Ангар().Золото().Получ())
		_бот["fuel"] = fmt.Sprint(бот.Ангар().Топливо().Получ())
		рез = append(рез, _бот)
	}
	return кнт.JSON(рез)
}
