// package root -- объект рута
package root

import (
	"fmt"
	"log"
	"strings"
	"time"

	"wartank/desktop/root/win_root_login"
	"wartank/desktop/root/win_root_set"
	"wartank/pkg/components/safebool"
	"wartank/pkg/types"
)

// Root -- объект рута
type Root struct {
	desktop      types.IDesktop
	ws           types.IWebSocket
	isLogin      *safebool.SafeBool
	isPassSet    *safebool.SafeBool
	winRootMake  *win_root_set.WinRootMake
	winRootLogin *win_root_login.WinRootLogin
}

// NewRoot -- вовзращает новый объект рута
func NewRoot(desktop types.IDesktop) (*Root, error) {
	log.Println("NewRoot()")
	if desktop == nil {
		return nil, fmt.Errorf("NewRoot(): IDesktop == nil")
	}
	sf := &Root{
		desktop:   desktop,
		ws:        desktop.Ws(),
		isLogin:   safebool.NewSafeBool(),
		isPassSet: safebool.NewSafeBool(),
	}
	sf.checkRoot()
	return sf, nil
}

// Проверяет, есть ли рут в системе
func (sf *Root) checkRoot() {
	log.Println("Root.checkRoot()")
	for { // Цикл ожидания рут-пароля (если его нет)
		isExists := sf.checkIsExists()
		if !isExists {
			sf.makePassRoot() // Раз пользователь сам создал пароль, то и проверка логина не нужна
			return
		}
		// Пароля уже есть, проверяем логин
		sf.checkLogin()
		return
	}

	// Запрос пароля рута

	// winUsers, err := win_users.NewWinUsers(sf.desktop)
	// if err != nil {
	// 	log.Printf("Root.checkRoot(): in create WinUsers, err=\n\t%v\n", err)
	// 	return
	// }
	// go winUsers.Run()
}

// Проверка логина
func (sf *Root) checkLogin() {
	log.Println("Root.checkLogin()")
	sf.makeWinLogin()
	strPass := sf.winRootLogin.GetPass()
	dictReq := make(map[string]string)
	dictReq["pass"] = strPass
	for {
		dictResp, err := sf.ws.Call("/root/password/check", dictReq)
		if err != nil {
			err = fmt.Errorf("Root.checkLogin(): при выполнении запроса, err=\n\t%w", err)
			sf.winRootLogin.SetError(err)
			time.Sleep(time.Second * 2)
			continue
		}
		log.Printf("WinRootLogin.onCheckPass(): resp=%q\n", dictResp)
		strErr := dictResp["err"]
		if strErr != "" {
			err = fmt.Errorf("Root.checkLogin(): при сравнении паролей, err=\n\t%q", strErr)
			sf.winRootLogin.SetError(err)
			time.Sleep(time.Second * 2)
			for {
				oldPass := strPass
				strPass = sf.winRootLogin.GetPass()
				if oldPass != strPass {
					break
				}
				time.Sleep(time.Millisecond * 100)
			}
			dictReq["pass"] = strPass
			continue
		}
		// Всё ништяк
		sf.winRootLogin.Close()
		sf.isPassSet.Set()
		return
	}
}

// Показывает окно логина
func (sf *Root) makeWinLogin() {
	log.Println("Root.makeWinLogin()")
	var err error
	for {
		sf.winRootLogin, err = win_root_login.NewWinRootLogin(sf.desktop)
		if err != nil {
			log.Printf("Root.makeWinLogin(): in create WinRootLogin, err=\n\t%v\n", err)
			time.Sleep(time.Second * 2)
			continue
		}
		break
	}
	go sf.winRootLogin.Run()
}

// Проверка на существование пароля рута
func (sf *Root) checkIsExists() bool {
	log.Println("Root.checkIsExists()")
	var strErr string
	for {
		dictRoot, err := sf.ws.Read("/root/password/is_exists")
		if err != nil {
			log.Printf("Root.checkRoot(): in get password root, err=\n\t%v\n", err)
			time.Sleep(time.Second * 2)
			continue
		}
		strErr = dictRoot["err"]
		if strings.Contains(strErr, "leveldb: not found") {
			log.Printf("Root.checkRoot(): первый запуск, пароль рута не задан\n")
			return false
		}
		strIsExists := dictRoot["/root/password/is_exists"]
		if strIsExists == "true" {
			return true
		}
		return false
	}
}

// Создаёт пароль рута
func (sf *Root) makePassRoot() {
	log.Println("Root.makePassRoot()")
	sf.makeWinRootMake()
	strPass := sf.winRootMake.GetPass()
	dictReq := make(map[string]string)
	dictReq["pass"] = strPass
	for {
		err := sf.ws.Write("/root/password/set", dictReq)
		if err != nil {
			sf.winRootMake.SetError(err)
			time.Sleep(time.Second * 2)
			continue
		}
		sf.winRootMake.Close()
		break
	}
}

// Показывает окно создания пароля рута
func (sf *Root) makeWinRootMake() {
	var err error
	for {
		sf.winRootMake, err = win_root_set.NewWinRootMake(sf.desktop)
		if err == nil {
			go sf.winRootMake.Run()
			return
		}
		log.Printf("Root.makeWinRootMake(): in create WinRoot, err=\n\t%v\n", err)
		time.Sleep(time.Second * 2)
		continue
	}
}
