package ui

import (
	"errors"
	"fmt"
	"go_dreamfactory/cmd/v2/lib/common"
	os_storage "go_dreamfactory/cmd/v2/lib/storage"
	"go_dreamfactory/cmd/v2/service"
	"go_dreamfactory/cmd/v2/service/observer"
	"os/exec"
	"path/filepath"
	"runtime"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	fyne_storage "fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"github.com/sirupsen/logrus"
)

type appGen struct {
	appAdapter

	obs      observer.Observer
	goList   *common.ItemList
	jsonList *common.ItemList
}

func (this *appGen) LazyInit(ptService service.PttService, obs observer.Observer) error {
	this.obs = obs
	this.goList = common.NewItemList()
	this.jsonList = common.NewItemList()

	this.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_GEN, theme.ContentCopyIcon(), nil)

	storage, _ := os_storage.NewOSStorage()
	conf, err := storage.LoadConfig()
	if err != nil {
		return err
	}

	content := container.NewMax()
	content.Objects = []fyne.CanvasObject{}

	serverAddr := widget.NewEntry()
	serverAddr.PlaceHolder = "服务器地址 例如: 10.0.1.11"

	projectDir := widget.NewEntry()
	projectDir.PlaceHolder = `项目目录 例如: E:\projects\workspace\go_dreamfactory\`

	workDir := widget.NewEntry()
	workDir.PlaceHolder = `LuBan目录 例如: E:\svn\dreamworks\client\dreamworks\ExcelFile\`

	// client
	client := widget.NewEntry()
	client.Text = `Luban.Client\Luban.Client.exe`
	client.PlaceHolder = `配置Luban Client.exe路径`

	//define
	define := widget.NewEntry()
	define.PlaceHolder = "定义文件"
	define.Text = `Defines\\__root__.xml`

	// output
	outputCodeDir := widget.NewEntry()
	outputCodeDir.Text = `sys\configure\structs`
	outputJsonDir := widget.NewEntry()
	outputJsonDir.Text = `bin\json`

	//input
	inputDir := widget.NewEntry()
	inputDir.Text = "Datas"

	tmpDir := widget.NewEntry()
	tmpDir.Text = filepath.Join(`c:\tmp\`)
	tmpDir.PlaceHolder = "临时目录,不要和工作目录和项目目录重复"

	//genType
	var genTypeText string
	genType := widget.NewSelect([]string{"go", "json", "all"}, func(s string) {
		genTypeText = s
	})
	genType.PlaceHolder = "生成类型"

	if conf.LubanConf != nil {
		serverAddr.Text = conf.LubanConf.ServerAddr
		projectDir.Text = conf.LubanConf.ProjectDir
		workDir.Text = conf.LubanConf.WorkDir
		client.Text = conf.LubanConf.Client
		genType.Selected = conf.LubanConf.GenType
		genTypeText = conf.LubanConf.GenType
		tmpDir.Text = conf.LubanConf.TmpDir
	}

	form := widget.NewForm(
		widget.NewFormItem("服务地址", serverAddr),
		widget.NewFormItem("项目目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() {
			openFolder(projectDir, toolWin.w)
		}), projectDir)),
		widget.NewFormItem("工作目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() {
			openFolder(workDir, toolWin.w)
		}), workDir)),
		widget.NewFormItem("LuBan Cli", client),
		widget.NewFormItem("输入目录", inputDir),
		widget.NewFormItem("输出Code目录", outputCodeDir),
		widget.NewFormItem("输出JSON目录", outputJsonDir),
		widget.NewFormItem("临时目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() {
			openFolder(tmpDir, toolWin.w)
		}), tmpDir)),
		widget.NewFormItem("生成类型", genType),
	)

	getType := func() string {
		if genTypeText == "" {
			return ""
		} else {
			if genTypeText == "go" {
				return "code_go_json"
			} else if genTypeText == "json" {
				return "data_json"
			} else if genTypeText == "all" {
				return "code_go_json,data_json"
			}
		}
		return ""
	}

	saveBtn := widget.NewButtonWithIcon("保存配置", theme.DocumentSaveIcon(), func() {
		lubanconf := &os_storage.LubanConfig{
			ServerAddr:    serverAddr.Text,
			ProjectDir:    projectDir.Text,
			Client:        client.Text,
			WorkDir:       workDir.Text,
			InputDir:      inputDir.Text,
			OutputCodeDir: outputCodeDir.Text,
			OutputJsonDir: outputJsonDir.Text,
			GenType:       genTypeText,
			TmpDir:        tmpDir.Text,
		}
		conf.LubanConf = lubanconf
		if err := storage.StoreConfig(conf); err != nil {
			logrus.WithField("err", err).Debug("保存配置")
		}
		logrus.Debug("save luban conf")
	})

	//go
	this.goList.TitleLabel = widget.NewLabel("Go文件")
	this.goList.TitleLabel.Hide()
	// 复选列表
	this.goList.ItemList = this.goList.CreateDefaultCheckList()

	// 覆盖 -go
	go_allSelBtn := &widget.Button{Icon: theme.CheckButtonCheckedIcon()}
	go_allCancelBtn := &widget.Button{Icon: theme.CheckButtonIcon()}
	go_overrideBtn := &widget.Button{Text: "覆盖", Icon: theme.ConfirmIcon()}
	go_overrideBtn.Hide()
	go_allSelBtn.Hide()

	// 覆盖
	go_overrideBtn.OnTapped = func() {
		go_overrideBtn.Disable()
		defer func() {
			go_overrideBtn.Enable()
			this.goList.ItemList.Refresh()
		}()
		for _, v := range this.goList.SelItemIds {
			// logrus.WithField("path1", filepath.Join(tmpDir.Text, "go", v)).Debug("copy go")
			// logrus.WithField("path2", filepath.Join(projectDir.Text, outputCodeDir.Text, v)).Debug("copy go")
			_, err := common.Copy(filepath.Join(tmpDir.Text, "go", v),
				filepath.Join(projectDir.Text, outputCodeDir.Text, v))
			if err != nil {
				logrus.Error(err)
				return
			}
			this.goList.DeleteItem(v)
		}
		this.goList.ChangeFileCount()
	}

	//取消checked
	go_allCancelBtn.OnTapped = func() {
		defer func() {
			go_allCancelBtn.Hide()
			go_allSelBtn.Show()
		}()
		this.goList.SelItemIds = []string{}
		for i, v := range this.goList.CachedList.Items {
			this.goList.CachedList.Items[i].Checked = false
			this.goList.ItemList.UpdateItem(i, widget.NewCheck(v.Text, nil))
		}
		this.goList.ChangeFileCount()
		this.goList.ItemList.Refresh()
	}

	//选择所有
	go_allSelBtn.OnTapped = func() {
		defer func() {
			go_allCancelBtn.Show()
			go_allSelBtn.Hide()
		}()
		for i, v := range this.goList.CachedList.Items {
			this.goList.CachedList.Items[i].Checked = true
			this.goList.SelItemIds = append(this.goList.SelItemIds, v.Text)
			this.goList.ItemList.UpdateItem(i, widget.NewCheck(v.Text, nil))
		}
		this.goList.ChangeFileCount()
		// this.goList.titleLabel.SetText(fmt.Sprintf("(%d/%d)", len(this.goList.selItemIds), this.goList.fileTotal))
		this.goList.ItemList.Refresh()
	}

	// json
	this.jsonList.TitleLabel = widget.NewLabel("Json文件")
	this.jsonList.TitleLabel.Hide()
	// 复选列表
	this.jsonList.ItemList = this.jsonList.CreateDefaultCheckList()

	// 覆盖 -json
	json_allSelBtn := &widget.Button{Icon: theme.CheckButtonCheckedIcon()}
	json_allCancelBtn := &widget.Button{Icon: theme.CheckButtonIcon()}
	json_overrideBtn := &widget.Button{Text: "覆盖", Icon: theme.ConfirmIcon()}
	json_overrideBtn.Hide()
	json_allSelBtn.Hide()

	// 点击覆盖按钮
	json_overrideBtn.OnTapped = func() {
		json_overrideBtn.Disable()
		defer func() {
			json_overrideBtn.Enable()
			this.jsonList.ItemList.Refresh()
		}()
		for _, v := range this.jsonList.SelItemIds {
			logrus.WithField("path", v).Debug("select json")
			// 	// logrus.WithField("path2", filepath.Join(projectDir.Text, outputJsonDir.Text, v)).Debug("copy json")
			_, err := common.Copy(filepath.Join(tmpDir.Text, "json", v),
				filepath.Join(projectDir.Text, outputJsonDir.Text, v))
			if err != nil {
				logrus.Error(err)
				return
			}
			this.jsonList.DeleteItem(v)
		}
		this.jsonList.ChangeFileCount()
	}

	//取消checked
	json_allSelBtn.OnTapped = func() {
		defer func() {
			json_allCancelBtn.Show()
			json_allSelBtn.Hide()
		}()
		list := this.jsonList
		list.SelItemIds = []string{}
		for i, v := range list.CachedList.Items {
			list.CachedList.Items[i].Checked = false
			list.ItemList.UpdateItem(i, widget.NewCheck(v.Text, nil))
		}
		this.jsonList.ChangeFileCount()
		list.ItemList.Refresh()
	}

	//选择所有
	json_allCancelBtn.OnTapped = func() {
		defer func() {
			json_allCancelBtn.Hide()
			json_allSelBtn.Show()
		}()
		list := this.jsonList
		for i, v := range list.CachedList.Items {
			list.CachedList.Items[i].Checked = true
			list.SelItemIds = append(list.SelItemIds, v.Text)
			list.ItemList.UpdateItem(i, widget.NewCheck(v.Text, nil))
		}
		list.ChangeFileCount()
		list.ItemList.Refresh()
	}

	// 资源管理器
	explorBtn := &widget.Button{Text: "资源管理器", Icon: theme.FolderIcon()}
	explorBtn.OnTapped = func() {
		OpenExplor(filepath.Join(workDir.Text, inputDir.Text))
	}

	genBtn := &widget.Button{Text: "生成", Icon: theme.ConfirmIcon()}
	genBtn.OnTapped = func() {
		genBtn.Disable()
		defer func() {
			genBtn.Enable()
			go_allCancelBtn.Show()
			go_allSelBtn.Hide()
			json_allCancelBtn.Show()
			json_allSelBtn.Hide()
		}()
		if runtime.GOOS != "windows" {
			dialog.ShowError(errors.New("no support "+runtime.GOOS), toolWin.w)
			return
		}

		if genTypeText == "" {
			dialog.ShowError(errors.New("类型未选择"), toolWin.w)
			return
		}

		changeGo := func() {
			this.goList.ChangeItem(filepath.Join(tmpDir.Text, "go"), filepath.Join(projectDir.Text, outputCodeDir.Text))
			this.goList.TitleLabel.SetText(fmt.Sprintf("(%d/%d个)", len(this.goList.SelItemIds), this.goList.ItemTotal))
			go_overrideBtn.Show()
			this.goList.TitleLabel.Show()
		}

		changeJson := func() {
			this.jsonList.ChangeItem(filepath.Join(tmpDir.Text, "json"), filepath.Join(projectDir.Text, outputJsonDir.Text))
			this.jsonList.TitleLabel.SetText(fmt.Sprintf("(%d/%d)", len(this.jsonList.SelItemIds), this.jsonList.ItemTotal))
			json_overrideBtn.Show()
			this.jsonList.TitleLabel.Show()
		}

		gen := func() {
			commandStr := `%s -h %s -j cfg --  -d %s --input_data_dir %s  --output_code_dir %s  --output_data_dir %s --gen_types %s  --go:bright_module_name bright  -s server`

			arg := fmt.Sprintf(commandStr,
				filepath.Join(workDir.Text, client.Text),
				serverAddr.Text,
				filepath.Join(workDir.Text, define.Text),
				filepath.Join(workDir.Text, inputDir.Text),
				filepath.Join(tmpDir.Text, "go"),
				filepath.Join(tmpDir.Text, "json"),
				getType(),
			)

			logrus.Debug(arg)
			c := exec.Command("cmd.exe", "/c", arg)
			if err := c.Run(); err != nil {
				dialog.ShowError(err, toolWin.w)
				return
			}

			// 更新列表
			if genTypeText == "go" {
				changeGo()
			} else if genTypeText == "json" {
				changeJson()
			} else if genTypeText == "all" {
				changeGo()
				changeJson()
			}
		}

		dc := dialog.NewConfirm("提示", "Excel文件需要更新吗?", func(b bool) {
			if !b {
				gen()
				return
			}

			OpenExplor(filepath.Join(workDir.Text, inputDir.Text))
		}, toolWin.w)
		dc.SetDismissText("不更新")
		dc.SetConfirmText("更新")
		dc.Show()
	}

	//使用说明
	desBtn := widget.NewButtonWithIcon("", theme.QuestionIcon(), func() {
		quesWin := fyne.CurrentApp().NewWindow("使用说明")
		quesWin.SetContent(widget.NewRichTextFromMarkdown(
			`
		1. SVN更新excel文件
		2. 配置Luban(已做可忽略)
		3. 选择**生成类型**,单击生成
		4. 选择要覆盖的文件
		`))
		quesWin.Resize(fyne.NewSize(350, 200))
		quesWin.SetFixedSize(true)
		quesWin.CenterOnScreen()
		quesWin.Show()
	})

	// layout
	left := container.NewVBox(form, container.NewHBox(&layout.Spacer{}, desBtn, saveBtn, &layout.Spacer{}, explorBtn, genBtn))
	right := container.NewGridWithColumns(2,
		container.NewBorder(
			container.NewHBox(go_allSelBtn, go_allCancelBtn, go_overrideBtn, widget.NewLabel("Go文件"), this.goList.TitleLabel),
			nil, nil, nil,
			this.goList.ItemList),
		container.NewBorder(
			container.NewHBox(json_allSelBtn, json_allCancelBtn, json_overrideBtn, widget.NewLabel("Json文件"), this.jsonList.TitleLabel),
			nil, nil, nil,
			this.jsonList.ItemList))

	content.Objects = append(content.Objects, container.NewGridWithColumns(2, left, right))

	this.tabItem.Content = content
	return nil
}

// 打开目录
func openFolder(entry *widget.Entry, w fyne.Window) {
	dConf := dialog.NewFolderOpen(func(lu fyne.ListableURI, err error) {
		if lu == nil {
			return
		}
		entry.Text = lu.Path()
		entry.Refresh()
	}, w)
	luri, _ := fyne_storage.ListerForURI(fyne_storage.NewFileURI("."))
	dConf.SetLocation(luri)
	dConf.SetConfirmText("打开")
	dConf.SetDismissText("取消")
	dConf.Resize(fyne.NewSize(750, 500))
	dConf.Show()
}

func openFile(entry *widget.Entry, w fyne.Window) {
	dConf := dialog.NewFileOpen(func(lu fyne.URIReadCloser, err error) {
		if lu == nil {
			return
		}
		entry.SetText(lu.URI().Path())
		entry.Refresh()
	}, w)
	dConf.SetConfirmText("打开")
	dConf.SetDismissText("取消")
	dConf.SetFilter(fyne_storage.NewExtensionFileFilter([]string{".exe"}))
	dConf.Resize(fyne.NewSize(750, 500))
	dConf.Show()
}

func (a *appGen) GetAppName() string {
	return common.TOOLBAR_GEN
}
func(a *appGen) Icon() fyne.Resource{
	return theme.ContentCopyIcon()
}