package bot_net_login

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"wartank/pkg/types"
	"wartank/server/serv_bots/warbot/warbot_net/bot_cookie"
)

/*
	Исходник предоставляет тип для сетевого входа на сервер.
*/

type IBotNet interface {
	Client() *http.Client
	Cookie() *bot_cookie.BotCookie
}

// BotNetLogin -- объект сетевого входа на сервер
type BotNetLogin struct {
	bot    types.IServBot
	conn   *http.Client
	cookie types.IBotCookie
}

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

	sf := &BotNetLogin{
		bot:    bot,
		conn:   bot.BotNet().Conn(),
		cookie: bot.BotNet().Cookie(),
	}
	return sf, nil
}

// Connect -- должен вызываться один раз и работать в отдельном потоке
func (sf *BotNetLogin) Connect() (err error) {
	// _mt.Println("\n===BotNetLogin.Connect()===")
	linkBegin, err := sf.getMainPage()
	if err != nil {
		return fmt.Errorf("BotNetLogin.Connect(): при получении главной страницы, err=\n\t%w", err)
	}
	switch linkBegin != "" {
	case true: // Это вход на базу
		strBodyLogin, err := sf.getPageLogin(linkBegin)
		if err != nil {
			return fmt.Errorf("BotNetLogin.Connect(): при получении страницы логина, err=\n\t%w", err)
		}
		if err = sf.makePostLogin(strBodyLogin); err != nil {
			return fmt.Errorf("BotNetLogin.Connect(): при выполнении логина, err=\n\t%w", err)
		}
		return nil
	default: // Логин уже был
		req, err1 := http.NewRequest("GET", "http://wartank.ru/angar", nil)
		if err1 != nil {
			return fmt.Errorf("BotNetLogin.Connect(): in get page angar, err=\n\t%w", err1)

		}
		resp, err2 := sf.conn.Do(req)
		defer func() {
			err3 := resp.Body.Close()
			if err3 != nil {
				err = fmt.Errorf("BotNetLogin.Connect(): in close body, err=\n\t%w", err3)
			}
		}()
		if err2 != nil {
			return fmt.Errorf("BotNetLogin.Connect(): in make request, err=\n\t%w", err2)
		}
		_, err := io.ReadAll(resp.Body)
		if err != nil {
			return fmt.Errorf("BotNetLogin.Connect(): in read body response, err=\n\t%w", err)
		}
	}
	return nil
}

// Прочитать главную страницу для получения кукисов
func (sf *BotNetLogin) getMainPage() (linkBegin string, err error) {
	// _mt.Println("\BotNetLogin.getMainPage()")
	resp, err := sf.conn.Get("http://wartank.ru/")
	defer func() {
		if _panic := recover(); _panic != nil {
			err = fmt.Errorf("BotNetLogin.getMainPage(): перехвачена паника в конце вызова главной страницы, panic=%v", _panic)
		}
	}()
	defer func() {
		err = resp.Body.Close()
		if err != nil {
			err = fmt.Errorf("NetLogin.getMainPage(): при закрытии тела ответапосле запроса главной страницы,err=%w", err)
		}
	}()
	if err != nil {
		return "", fmt.Errorf("BotNetLogin.getMainPage(): err=\n\t%w", err)
	}
	// Получить куки из ответа
	cookies := resp.Cookies()
	if len(cookies) > 0 {
		if err = sf.cookie.Set(cookies); err != nil {
			return "", fmt.Errorf("BotNetLogin.getMainPage(): при установки куки, err=\n\t%w", err)
		}
	}
	binData, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("BotNetLogin.getMainPage(): при чтении тела ответа, err=\n\t%w", err)
	}
	// Вырезать из тела страницы ссылку на вход
	lstStr := strings.Split(string(binData), "\n")
	var strOut string
	for _, strLink := range lstStr {
		if strings.Contains(strLink, `w:id="showSigninLink"`) {
			strOut = strLink
			break
		}
	}
	if strOut == "" { // Уже был логин
		return "", nil
	}
	{ // Получить ссылку на вход
		lstLink := strings.Split(strOut, `href="`)
		lstLink = strings.Split(lstLink[1], `"><span><span>`)
		linkBegin = "http://wartank.ru/" + lstLink[0]
	}
	return linkBegin, nil
}

// Получает страницу логина
func (sf *BotNetLogin) getPageLogin(linkBegin string) (strBodyLogin string, err error) {
	// _mt.Println("\BotNetLogin.getPageLogin()")
	resp, err := sf.conn.Get(linkBegin)
	defer func() {
		err = resp.Body.Close()
		if err != nil {
			err = fmt.Errorf("NetLogin.getPageLogin(): in close body,err=%w", err)
		}
	}()
	if err != nil {
		return "", fmt.Errorf("NetLogin.getPageLogin(): in mske GET-request for send login page, err=\n\t%w", err)
	}
	// sf.cookie = resp.Cookies()
	binData, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("NetLogin.getPageLogin(): in read body response, err=\n\t%w", err)
	}
	strBodyLogin = string(binData)
	// sf.app.AddLog(fmt.Sprintf("BotNetLogin.getPageLogin(): page_login=\n%v\n\n", strBodyLogin))
	return strBodyLogin, nil
}

// Выполняет логин через POST-запрос
func (sf *BotNetLogin) makePostLogin(strBody string) (err error) {
	// _mt.Println("\BotNetLogin.makePostLogin()")
	var strBodyMain string
	{ // Получить форму логина
		lstLogin := strings.Split(strBody, "\n")
		for _, strForm := range lstLogin {
			if strings.Contains(strForm, `<form w:id="loginForm" id=`) {
				strBodyMain = strForm
				break
			}
		}
	}
	var postLink string
	{ // Получить ссылку на POST-запрос
		lstLink := strings.Split(strBodyMain, ` action="`)
		strLink := lstLink[1]
		lstLink = strings.Split(strLink, `"><div style=`)
		postLink = "http://wartank.ru/" + lstLink[0]
	}
	{ // Конструируем ПОСТ-форму логина
		form := url.Values{}
		form.Add("id1_hf_0", "")
		form.Add("login", sf.bot.Name())
		form.Add("password", sf.bot.Pass())

		resp, err := sf.conn.PostForm(postLink, form)
		defer func() {
			_ = resp.Body.Close()
		}()
		if err != nil {
			return fmt.Errorf("BotNetLogin.makePostLogin(): in get POST-login response, err=\n\t%w", err)
		}
		if _, err = io.ReadAll(resp.Body); err != nil {
			return fmt.Errorf("BotNetLogin.makePostLogin(): in read body POST-login response, err=\n\t%w", err)
		}
		urlObj, _ := url.Parse("http://wartank.ru/")
		sf.conn.Jar.SetCookies(urlObj, sf.cookie.Get())
	}
	return nil
}
