// package win_main -- главное окно приложения
package win_main

import (
	_ "embed"
	"fmt"
	"log"
	"net/url"
	"runtime"
	"sync"
	"time"

	"github.com/zserge/lorca"

	// "wartank/desktop/win_users"
	"wartank/pkg/components/safebool"
	"wartank/pkg/types"
)

const (
	strWinMainName = "win_main" // Контрольная строка для сторожа потоков
)

//go:embed win_main.html
var strWinHtml string

// WinMain -- главное окно приложения
type WinMain struct {
	desktop types.IDesktop
	store   types.IStore
	win     lorca.UI
	block   sync.Mutex
	isWork  *safebool.SafeBool
	ws      types.IWebSocket
}

// NewWinMain -- возвращает новое окно десктопа
func NewWinMain(desktop types.IDesktop) (*WinMain, error) {
	if desktop == nil {
		return nil, fmt.Errorf("NewWinMain(): IDesktop == nil")
	}
	sf := &WinMain{
		desktop: desktop,
		store:   desktop.Store(),
		isWork:  safebool.NewSafeBool(),
		ws:      desktop.Ws(),
	}
	args := []string{}
	if runtime.GOOS == "linux" {
		args = append(args, "--class=Lorca")
	}
	var err error
	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
	if err != nil {
		return nil, fmt.Errorf("NewWinMain(): in create win, err=\n\t%w", err)
	}
	go sf.close()
	return sf, nil
}

// Работает в отдельном потоке, главный цикл окна
func (sf *WinMain) Run() {
	log.Println("WinMain.Run()")
	sf.win.Bind("close_win", sf.onClose)
	sf.win.Bind("bot_list", sf.onUsers)
	go sf.timeServer()
	<-sf.win.Done() // Ожидание закрытия окна
	sf.desktop.CancelApp()
}

// Открывает окно с пользователями
func (sf *WinMain) onUsers() {
	log.Println("WinMain.onUsers()")
	go sf.desktop.DictBot().Show()
}

// Проверяет наличие работающего сервера, работает в отдельном потоке
func (sf *WinMain) timeServer() {
	for {
		time.Sleep(time.Second * 2)
		timeBeg := time.Now().UTC().UnixMicro()
		dictResp, err := sf.ws.Read("/server/time")
		if err != nil {
			log.Printf("WinMain.timeServer(): in send request to server, err=\n\t%v\n", err)
			sf.desktop.CancelApp()
			return
		}
		timeEnd := time.Now().UTC().UnixMicro() - timeBeg
		strErr := dictResp["err"]
		if strErr != "" {
			js := fmt.Sprintf(`
		function SetTimeServer(){
			var _el = document.getById("/server/time");
			_el.innerText=%q;
		}
		SetTimeServer()
		`, err)
			sf.win.Eval(js)
			continue
		}
		strTime := dictResp["/server/time"]

		js := fmt.Sprintf(`
		function SetTimeServer(){
			var _el = document.getElementById("/server/time");
			_el.innerText=%q;
		}
		SetTimeServer()
		`, strTime)
		sf.win.Eval(js)

		js = fmt.Sprintf(`
		function SetPingServer(){
			var _el = document.getElementById("/server/ping");
			_el.innerText="%v мкСек";
		}
		SetPingServer()
		`, timeEnd)
		sf.win.Eval(js)
	}
}

// Закрывает приложение
func (sf *WinMain) onClose() {
	log.Println("WinMain.onClose()")
	sf.win.Close()
}

// close -- ожидает отмены глобального контекста
func (sf *WinMain) close() {
	<-sf.desktop.CtxApp().Done()
	log.Println("WinMain.close()")
	sf.block.Lock()
	defer sf.block.Unlock()
	if !sf.isWork.Get() {
		return
	}
	sf.isWork.Reset()
	sf.win.Close()
	sf.desktop.Wg().Done(strWinMainName)
}
