package ui

import (
	"errors"
	"fmt"
	"go_dreamfactory/cmd/v2/lib/common"
	"go_dreamfactory/cmd/v2/lib/storage"
	"go_dreamfactory/cmd/v2/service/observer"
	"go_dreamfactory/comm"
	// "go_dreamfactory/modules/user"
	"go_dreamfactory/pb"
	"strings"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"github.com/BabySid/gobase"
	"github.com/Pallinder/go-randomdata"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cast"
)

var (
	globalWin *MainWindowImpl
)

type MainWindow interface {
	WindowInterface
}

type MainWindowImpl struct {
	UIImpl
	WindowDefaultOptions
	parent fyne.Window
	w      fyne.Window
	tb     *toolBar      //工具条
	toys   *toys         // side
	sb     *statusBar    //状态栏
	at     *appContainer //tabs
	mm     *mainMenu     //菜单
}

func NewMainWindow(ui *UIImpl, parent fyne.Window) MainWindow {
	gobase.NewScheduler().Start()
	gobase.RegisterAtExit(gobase.GlobalScheduler.Stop)
	mw := &MainWindowImpl{
		UIImpl: *ui,
		parent: parent,
	}

	globalWin = mw

	ui.obs.AddListener(observer.EVENT_PING, observer.Listener{
		OnNotify: func(data interface{}, args ...interface{}) {
			ui.obs.Remove(observer.EVENT_PING)
			logrus.Debug("即将与服务器断开链接")
			conf := dialog.NewConfirm("链接中断", data.(error).Error(), func(
				b bool) {
				ui.app.Quit()
			}, globalWin.w)
			conf.SetDismissText("取消")
			conf.SetConfirmText("退出")
			conf.Show()
		},
	})

	return mw
}

// createWindowContainer create a container with the window content
func (ui *MainWindowImpl) createWindowContainer() {
	// create main layout

	// status bar
	ui.sb = newStatusBar()

	// tool bar
	toolbar := widget.NewToolbar(
	// widget.NewToolbarAction(theme.MediaVideoIcon(), func() {
	// 	openApp(ui.at, common.TOOLBAR_MONITOR)
	// }),
	// widget.NewToolbarAction(theme.DocumentIcon(), func() {
	// 	openApp(ui.at, common.TOOLBAR_TESTER)
	// }),
	// widget.NewToolbarAction(theme.StorageIcon(), func() {
	// 	openApp(ui.at, common.TOOLBAR_AUTO)
	// }),
	// widget.NewToolbarSpacer(),
	// widget.NewToolbarAction(theme.FileIcon(), func() {
	// 	newLogViewer().Win.Show()
	// }),
	)
	ui.tb = newToolBar(toolbar)

	// Fun Toys
	ui.toys = newToys(ui.obs)

	// Main Menu
	ui.mm = newMainMenu()
	ui.w.SetMainMenu(ui.mm.MainMenu)

	// main app tabs
	ui.at = newAppContainer(appRegister, ui.pttService, ui.obs)
	content := container.NewBorder(ui.tb.toolbar, ui.sb.widget, nil, ui.toys.widget, ui.at)
	ui.w.SetContent(content)
	ui.w.CenterOnScreen()
	ui.w.SetCloseIntercept(ui.quiteHandle)
}

func (ui *MainWindowImpl) SetStatusMsg(msg string) {
	ui.sb.setMessage(fmt.Sprintf("err:%s", msg))
}

func (ui *MainWindowImpl) quiteHandle() {
	dialog.ShowConfirm("提示", "确定退出吗", func(b bool) {
		if !b {
			return
		}
		ui.app.Quit()
	}, ui.w)
}

// CreateWindow ....
func (ui *MainWindowImpl) CreateWindow(_ string, width, height float32, _ bool) {
	// init window
	title := fmt.Sprintf(common.APP_WIN_TITLE, "登录", ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME)
	w := ui.app.NewWindow(title)
	ui.AddWindow("main", w)
	ui.w = w

	if ui.windowAspect == common.WindowAspect_FullScreen {
		w.SetFullScreen(true)
	} else {
		w.Resize(fyne.NewSize(width, height))
	}

	// w.SetMaster()
	w.CenterOnScreen()
	w.SetCloseIntercept(func() {
		ui.parent.Show()
	})
	_ = ui.createChooseServerPopUp(w)
}

// createChooseServerPopUp
func (ui *MainWindowImpl) createChooseServerPopUp(w fyne.Window) error {
	ch := make(chan string)

	title := fmt.Sprintf(common.APP_WIN_TITLE, "选服", ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME)
	selServerWin := ui.createChooseServerWindow(title, ch)

	go func() {
		data := <-ch
		selServerWin.Hide()
		ui.NewWelcomeLabel(data)
		ui.w.Show()
	}()
	return nil
}

func (ui *MainWindowImpl) configForm(w fyne.Window, call func()) *widget.Form {
	//区服编号
	sId := widget.NewEntry()
	//区服地址
	sAddr := widget.NewEntry()
	//区服名称
	sName := widget.NewEntry()
	configForm := widget.NewForm()
	configForm.AppendItem(widget.NewFormItem("区服编号", sId))
	configForm.AppendItem(widget.NewFormItem("区服地址", sAddr))
	configForm.AppendItem(widget.NewFormItem("区服名称", sName))

	configForm.OnSubmit = func() {
		defer func() {
			w.Close()
			call()
		}()
		ui.config.Servers = append(ui.config.Servers, &storage.ServerConfig{
			Name: sName.Text,
			SId:  sId.Text,
			Url:  sAddr.Text,
		})
		if err := ui.storage.StoreConfig(ui.config); err != nil {
			dialog.ShowError(err, w)
			return
		}
	}
	configForm.SubmitText = "保存配置"
	configForm.Refresh()
	return configForm
}

// createChooseServerWindow
func (ui *MainWindowImpl) createChooseServerWindow(title string, ch chan string) fyne.Window {
	w := fyne.CurrentApp().NewWindow(title)
	// choose server button func
	makeButton := func(s *storage.ServerConfig, parent fyne.Window) *widget.Button {
		btn := widget.NewButton(s.Name, func() {
			d := dialog.NewInformation("", common.INFO_WAIT, parent)
			d.SetDismissText(common.BUTTON_CANCEL)
			d.Show()

			logrus.WithFields(logrus.Fields{"server": s.Name, "sid": s.SId}).Debug("choose server")
			//conn server
			if err := ui.connService.WsConnect(s.Url); err != nil {
				d.Hide()
				dialog.ShowError(err, parent)
			} else {
				ch <- fmt.Sprintf("%s:%s", s.SId, s.Name)
			}
		})
		return btn
	}

	sGrid := container.NewGridWithColumns(2)

	if len(ui.config.Servers) == 0 {
		c := storage.NewDefaultConfig()
		ui.config.Servers = append(ui.config.Servers, c.Servers...)
	}

	if len(ui.config.Servers) != 0 {
		for _, s := range ui.config.Servers {
			box := makeButton(s, w)
			sGrid.Add(container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.DeleteIcon(), func() {
				defer func() {
					w.Close()
					ui.parent.Show()
				}()
				txt := box.Text
				for i, ss := range ui.config.Servers {
					if txt == ss.Name {
						ui.config.Servers = append(ui.config.Servers[:i], ui.config.Servers[i+1:]...)
						i--
					}
				}
				if err := ui.storage.StoreConfig(ui.config); err != nil {
					dialog.ShowError(err, w)
				}

			}), box))
		}
		sGrid.Add(widget.NewButtonWithIcon("", theme.ContentAddIcon(), func() {
			addWin := fyne.CurrentApp().NewWindow("添加区服")
			addWin.SetContent(ui.configForm(addWin, func() {
				w.Close()
				ui.parent.Show()
			}))
			addWin.SetFixedSize(true)
			addWin.Resize(fyne.NewSize(500, 200))
			addWin.Show()
			addWin.CenterOnScreen()
		}))
		w.SetContent(sGrid)
	} else {
		w.SetContent(ui.configForm(w, func() {
			w.Close()
			ui.parent.Show()
		}))
	}

	w.SetFixedSize(true)
	w.Resize(fyne.NewSize(500, 200))
	w.Show()
	w.SetCloseIntercept(func() {
		ui.parent.Show()
		w.Close()
	})
	w.CenterOnScreen()
	return w
}

// createLoginWin
func (ui *MainWindowImpl) createLoginWin(sid, sname string) {
	account := widget.NewEntry()
	// account.Text = "user8080" //default account

	items := []*widget.FormItem{
		widget.NewFormItem(common.LABEL_ACCOUNT, account),
	}

	dialog.ShowForm(common.FORM_TITLE_LOGIN, common.BUTTON_LOGIN, common.BUTTON_CANCEL, items, func(b bool) {
		if !b {
			logrus.Debug("cancel login")
		} else {
			if account.Text != "" {
				logrus.WithField("account", account.Text).Debug("submit login")
				ui.createWindowContainer()
				appName, err := ui.at.openDefaultApp(common.TOOLBAR_MONITOR)
				if err != nil {
					logrus.WithField("appName", appName).Error(err)
				}
				// hide toolbar
				ui.tb.toolbar.Hide()
				// call after ui.createWindowContainer
				ui.connService.ListenerPush()
				if errdata := ui.pttService.Login(sid, account.Text); errdata != nil {
					err := fmt.Errorf("login err: %v[%d]", errdata, int32(errdata.Code))
					dialog.ShowError(err, ui.w)
				} else {
					ui.obs.AddListener(observer.EVENT_REQ_RSP, observer.Listener{
						OnNotify: func(data interface{}, args ...interface{}) {
							if data == nil {
								return
							}
							msg := data.(*pb.UserMessage)
							if msg.MainType == string("user") &&
								msg.SubType == "login" {
								rsp := &pb.UserLoginResp{}
								if !comm.ProtoUnmarshal(msg, rsp) {
									logrus.Error("unmarshal err")
									return
								}

								//ping
								go func() {
									timer := time.NewTimer(10 * time.Second)
									for {
										if !timer.Stop() {
											select {
											case <-timer.C:
											default:
											}
										}
										timer.Reset(10 * time.Second)
										select {
										case <-timer.C:
											ui.pttService.Ping(sid, account.Text)
											continue
										}
									}
								}()
								// reset main window title
								subTitle := fmt.Sprintf("%s[%s]", sname, sid)
								ui.w.SetTitle(fmt.Sprintf(common.APP_WIN_TITLE, subTitle, ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME))
								ui.pttService.SetUser(rsp.Data, rsp.Ex)
								// isCreateRole
								if rsp.Data.Created {
									// set statusbar message
									ui.sb.setMessage(common.LABEL_WELCOME + rsp.Data.Binduid)
									// update userinfo
									ui.obs.Notify(observer.EVENT_USERINFO, ui.pttService.GetUser())
									// show toolbar
									ui.tb.toolbar.Show()
								} else {
									// create role
									ui.createRoleWindowPopUp()
								}
							} else if msg.MainType == "notify" && msg.SubType == "errornotify" {
								push := &pb.NotifyErrorNotifyPush{}
								if !comm.ProtoUnmarshal(msg, push) {
									logrus.Error("unmarsh err")
									return
								}

								if push.Code == pb.ErrorCode_UserLogined {
									cf := dialog.NewError(errors.New("【"+account.Text+"】账号已在其它终端登录,退出重新登录"), ui.w)
									cf.SetOnClosed(func() {
										ui.app.Quit()
									})
									cf.Show()
								}
							}
						},
					})
				}
			}
		}
	}, ui.w)
}

// createMainWindowMenu create the main window menu
func (ui *MainWindowImpl) createMainWindowMenu() *fyne.MainMenu {

	menuItems := []*fyne.MenuItem{}

	menu := fyne.Menu{
		Label: common.MENU_FILE,
		Items: menuItems,
	}

	return fyne.NewMainMenu(&menu)
}

// createRoleWindowPopUp
func (ui *MainWindowImpl) createRoleWindowPopUp() {
	nickname := widget.NewEntry()
	c := container.NewBorder(nil, nil, nil,
		widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), func() {
			nickname.SetText(randomdata.SillyName())
		}),
		nickname,
	)
	figure := widget.NewEntry()
	figure.PlaceHolder = "形象ID"
	figure.Text = "1"

	var gender int32
	genderSel := widget.NewSelect([]string{"男", "女"}, func(s string) {
		if s == "男" {
			gender = 0
		} else if s == "女" {
			gender = 1
		}
	})
	genderSel.Selected = "男"

	items := []*widget.FormItem{
		widget.NewFormItem("性别", genderSel),
		widget.NewFormItem("形象", figure),
		widget.NewFormItem(common.LABEL_NICKNAME, c),
	}

	d := dialog.NewForm(common.FORM_TITLE_CREATEROLE, common.BUTTON_OK, common.BUTTON_CANCEL, items, func(b bool) {
		if nickname.Text != "" {
			logrus.WithField("nickname", nickname.Text).Debug("submit crete role")
			if errdata := ui.pttService.CreateRole(nickname.Text, gender, cast.ToInt32(figure.Text)); errdata != nil {
				err := fmt.Errorf("login err: %v[%d]", errdata, int32(errdata.Code))
				dialog.ShowError(err, ui.w)
			} else {
				user := ui.pttService.GetUser()
				logrus.WithField("uid", user.DbUser.Uid).Debug("create role succ")
				ui.obs.Notify(observer.EVENT_USERINFO, ui.pttService.GetUser())
				ui.tb.toolbar.Show()
			}
		}
	}, ui.w)
	d.Resize(fyne.NewSize(300, 200))
	d.Show()
}

// NewWelcomeLabel
func (ui *MainWindowImpl) NewWelcomeLabel(data string) {
	p := strings.Split(data, ":")
	if len(p) != 2 {
		logrus.WithField("param", p).Error("choose service")
		return
	}
	c := container.NewCenter(container.NewVBox(
		widget.NewLabelWithStyle(fmt.Sprintf(common.LABEL_CHOOSE, p[0], p[1]),
			fyne.TextAlignCenter,
			fyne.TextStyle{Bold: true}),
		container.NewCenter(container.NewHBox(
			widget.NewButton(common.BUTTON_LOGIN, func() {
				ui.createLoginWin(p[0], p[1])
			}),
		)),
	))
	ui.w.SetContent(c)
	ui.w.SetCloseIntercept(func() {
		ui.w.Close()
		ui.parent.Show()
	})
}
