package ui

import (
	"fmt"
	"go_dreamfactory/cmd/v2/lib/common"
	pb2 "go_dreamfactory/cmd/v2/lib/pb"
	"go_dreamfactory/cmd/v2/model"
	"go_dreamfactory/cmd/v2/service"
	"go_dreamfactory/cmd/v2/service/observer"
	"go_dreamfactory/pb"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"github.com/sirupsen/logrus"
)

type appTester struct {
	appAdapter
	progress *widget.ProgressBarInfinite
}

func (a *appTester) GetAppName() string {
	return common.TOOLBAR_TESTER
}

func (a *appTester) disEnabled(t *model.TestCase) bool {
	return !t.Enabled
}

func (a *appTester) LazyInit(service service.PttService, obs observer.Observer) error {
	a.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_TESTER, theme.DocumentIcon(), nil)

	a.progress = widget.NewProgressBarInfinite()
	a.progress.Hide()

	content := container.NewMax()
	title := widget.NewLabel(common.APP_TESTCASE_TITLE)
	intro := widget.NewLabel("")
	intro.Wrapping = fyne.TextWrapWord
	caseContent := container.NewBorder(
		container.NewVBox(container.NewHBox(title), widget.NewSeparator(), intro), nil, nil, nil, content)

	setNav := func(t *model.TestCase) {
		defer a.progress.Hide()
		viewKey := fmt.Sprintf("%s.%s", t.MainType, t.SubType)
		title.SetText(fmt.Sprintf("> %s", viewKey))
		intro.SetText(t.Desc)
		content.Objects = []fyne.CanvasObject{}

		if view, ok := ViewRegister[viewKey]; ok {
			timeLbl := widget.NewLabel("time")
			resLog := widget.NewMultiLineEntry()
			view.Init(service, obs, globalWin.w, resLog)

			obs.AddListener(observer.EVENT_REQ_RSP, observer.Listener{
				OnNotify: func(data interface{}, args ...interface{}) {
					if data == nil {
						return
					}
					msg := data.(*pb.UserMessage)
					if t.MainType == msg.MainType && t.SubType == msg.SubType {
						if t.Print != nil {
							resLog.SetText(t.Print(msg))
						} else {
							resLog.SetText(msg.Data.String())
						}
					}
				},
			})

			obs.AddListener(observer.EVENT_RST, observer.Listener{
				OnNotify: func(data interface{}, args ...interface{}) {
					tm := data.(time.Time)
					cost := time.Since(tm)
					// logrus.WithFields(logrus.Fields{"Main": t.MainType, "Sub": t.SubType, "cost": cost}).Debug("耗时")
					timeLbl.Text = fmt.Sprintf("耗时:%v", cost)
					timeLbl.Refresh()
				},
			})

			resLog.Wrapping = fyne.TextWrapBreak
			formReq := view.CreateView(t)
			// required! Refresh updates the widget
			formReq.Refresh()
			formCard := widget.NewCard("", "", formReq)

			clearBtn := widget.NewButtonWithIcon(common.APP_TESTCASE_BTN_CLEARLOG, theme.DeleteIcon(), func() {
				resLog.SetText("")
			})

			resPanel := container.NewBorder(container.NewHBox(clearBtn, layout.NewSpacer(), timeLbl), nil, nil, nil, resLog)

			panel := container.NewVSplit(
				formCard,
				resPanel,
			)
			panel.Offset = 0.8
			content.Objects = append(content.Objects, panel)
		} else {
			logrus.WithFields(logrus.Fields{"mainType": t.MainType, "subType": t.SubType}).Warn("no view")
		}

		content.Refresh()
	}
	split := container.NewHSplit(a.makeNav(setNav), caseContent)
	split.Offset = 0.2
	a.tabItem.Content = container.NewBorder(nil, a.progress, nil, nil, split)
	return nil
}

func (a *appTester) makeNav(setNav func(testCase *model.TestCase)) fyne.CanvasObject {
	tree := &widget.Tree{
		ChildUIDs: func(uid string) (c []widget.TreeNodeID) {
			return pb2.CaseIndex[uid]
		},
		IsBranch: func(uid string) bool {
			children, ok := pb2.CaseIndex[uid]
			return ok && len(children) > 0
		},
		CreateNode: func(branch bool) fyne.CanvasObject {
			return widget.NewLabel("(empty)")
		},
		UpdateNode: func(uid string, branch bool, obj fyne.CanvasObject) {
			t, ok := pb2.CaseNav[uid]
			if !ok {
				logrus.WithField("id", uid).Warnf("Missing tutorial panel")
				return
			}
			if a.disEnabled(t) {
				obj.(*widget.Label).TextStyle = fyne.TextStyle{Italic: true}
				if branch { //parent
					obj.(*widget.Label).SetText(fmt.Sprintf("%s(dis0)", t.MainType))
				} else {
					// obj.(*widget.Label).SetText(fmt.Sprintf("%s(dis1)", t.SubType))
				}
			} else {
				if branch { //parent
					obj.(*widget.Label).TextStyle = fyne.TextStyle{Bold: true}
					if t.NavLabel != "" {
						obj.(*widget.Label).SetText(t.NavLabel)
					} else {
						obj.(*widget.Label).SetText(t.MainType)
					}
				} else {
					if t.NavLabel != "" {
						obj.(*widget.Label).SetText(t.NavLabel)
					} else {
						obj.(*widget.Label).SetText(t.SubType)
					}
				}

			}
		},
		OnSelected: func(uid string) {
			if t, ok := pb2.CaseNav[uid]; ok {
				logrus.WithFields(logrus.Fields{"mainType": t.MainType, "subType": t.SubType}).Debug("select")
				if a.disEnabled(t) {
					return
				}
				if t.SubType == "" {
					return
				}
				a.progress.Start()
				a.progress.Show()
				go setNav(t)
			}
		},
	}
	return container.NewBorder(nil, nil, nil, nil, tree)
}

func (a *appTester) ShortCut() fyne.Shortcut {
	return &desktop.CustomShortcut{KeyName: fyne.Key2, Modifier: desktop.AltModifier}
}

func (a *appTester) Icon() fyne.Resource {
	return theme.DocumentIcon()
}

func (a *appTester) Pressure() bool {
	return true
}
