// This is a simple example
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"go.wit.com/gui"
	"go.wit.com/log"

	"go.wit.com/lib/gadgets"
	"go.wit.com/lib/gui/repolist"
	"go.wit.com/lib/gui/shell"
)

type releaseStruct struct {
	box             *gui.Node
	group           *gui.Node
	grid            *gui.Node
	repo            *gadgets.OneLiner
	status          *gadgets.OneLiner
	readOnly        *gadgets.OneLiner
	notes           *gadgets.OneLiner
	version         *gadgets.OneLiner
	releaseVersionB *gui.Node
	reason          *gadgets.BasicEntry

	openrepo *gui.Node

	goGetB       *gui.Node
	checkGoSumB  *gui.Node
	checkDirtyB  *gui.Node
	makeRedomodB *gui.Node
	sendVersionB *gui.Node
	checkSafeB   *gui.Node
	whitelist    map[string]*repolist.RepoRow

	// store myself here. use myself to
	// do garbage go get tests and other potential junk
	guireleaser *repolist.RepoRow
}

func (w *autoType) Disable() {
	me.mainBox.Disable()
}

func (w *autoType) Enable() {
	me.mainBox.Enable()
}

func createReleaseBox(box *gui.Node) {
	initWhitelist()

	me.release.box = box.NewVerticalBox("vbox")
	me.release.group = me.release.box.NewGroup("Current Repo")
	me.release.grid = me.release.group.NewGrid("buildOptions", 0, 0)
	me.release.grid.NextRow()

	me.release.releaseVersionB = me.release.grid.NewButton("release version", func() {
		buttonDisable()
		if doRelease() {
			buttonEnable()
			log.Info("doRelease() worked")
		} else {
			log.Info("doRelease() failed")
		}
	})
	me.release.grid.NewButton("Find Next Releasable", func() {
		me.Disable()
		defer me.Enable()
		if findNext() {
			log.Info("findNext() found a repo")
			return
		}
	})
	me.release.grid.NextRow()

	me.release.repo = gadgets.NewOneLiner(me.release.grid, "repo")
	me.release.openrepo = me.release.grid.NewButton("Configure", func() {
		me.current.Status.Toggle()
	})
	me.release.openrepo.Disable()
	me.release.grid.NextRow()
	me.release.status = gadgets.NewOneLiner(me.release.grid, "status")
	me.release.grid.NextRow()
	me.release.readOnly = gadgets.NewOneLiner(me.release.grid, "read-only")
	me.release.grid.NextRow()
	me.release.notes = gadgets.NewOneLiner(me.release.grid, "notes")
	me.release.grid.NextRow()

	me.release.version = gadgets.NewOneLiner(me.release.grid, "version")
	me.release.grid.NextRow()

	me.release.reason = gadgets.NewBasicEntry(me.release.grid, "release reason")
	me.release.reason.SetText(me.releaseReasonS)
	me.release.grid.NextRow()

	me.autoWorkingPwd = gadgets.NewOneLiner(me.release.grid, "working directory (pwd)")
	me.release.grid.NextRow()
	me.userHomePwd = gadgets.NewOneLiner(me.release.grid, "user home")
	me.release.grid.NextRow()
	me.goSrcPwd = gadgets.NewOneLiner(me.release.grid, "go src home")
	me.release.grid.NextRow()

	homeDir, err := os.UserHomeDir()
	if err != nil {
		log.Warn("Error getting home directory:", err)
		homeDir = "/home/autotypist"
	}
	me.userHomePwd.SetText(homeDir)
	srcDir := filepath.Join(homeDir, "go/src")
	me.goSrcPwd.SetText(srcDir)

	testf := filepath.Join(srcDir, "go.wit.com/apps/guireleaser", "go.sum")
	if !shell.Exists(testf) {
		log.Info("go.sum missing", testf)
		panic("redo go.sum")
	}

	group := me.release.box.NewGroup("Run on Current Repo")
	grid := group.NewGrid("buildOptions", 0, 0)

	grid.NewButton("set to IGNORE", func() {
		// tmp := me.current.GoState()
		log.Info("trying to whitelist repo", me.current.GoPath())
		// me.current.SetGoState("IGNORE")
		me.release.whitelist[me.current.GoPath()] = me.current
	})

	me.release.checkGoSumB = grid.NewButton("checkValidGoSum()", func() {
		buttonDisable()
		checkValidGoSum(me.current)
		buttonEnable()
	})

	grid.NextRow()

	group = me.release.box.NewGroup("Process against all repos")
	grid = group.NewGrid("buildOptions", 0, 0)
	grid.NewButton("doRelease() all", func() {
		var worked bool = true
		buttonDisable()
		// rather than loop forever, at least limit this to the number of repos
		// incase something, somewhere, goes wrong
		duration := repolist.TimeFunction(func() {
			for n := 0; n <= len(me.repos.View.AllRepos()); n++ {
				if doRelease() {
					log.Info("doRelease() worked")
				} else {
					if me.release.status.String() == "ALL DONE?" {
						log.Info("maybe ALL DONE?")
						buttonEnable()
						worked = true
						break
					}
					log.Info("doRelease() failed")
					worked = false
					break
				}
			}
		})
		s := fmt.Sprint(duration)
		log.Info("release returned", worked, "and ran for", s)
		buttonEnable()
	})
	grid.NextRow()

	group = me.release.box.NewGroup("experimental and potentially dangerous stuff")
	grid = group.NewGrid("buildOptions", 0, 0)
	grid.NewButton("rm -f go.mod go.sum", func() {
		me.Disable()
		for _, repo := range me.repos.View.AllRepos() {
			if whitelist(repo.GoPath()) {
				continue
			}
			if repo.Status.ReadOnly() {
				continue
			}
			repo.Status.Run([]string{"rm", "-f", "go.mod", "go.sum"})
		}
		me.Enable()
	})

	grid.NewButton("git reset --hard", func() {
		me.Disable()
		for _, repo := range me.repos.View.AllRepos() {
			if whitelist(repo.GoPath()) {
				log.Warn("skipping whitelist", repo.Name())
				continue
			}
			log.Warn("running git reset --hard", repo.Name())
			repo.Status.Run([]string{"git", "reset", "--hard"})
		}
		me.Enable()
	})

	grid.NewButton("git ls-files |grep go.mod", func() {
		// var all []string
		for _, repo := range me.repos.View.AllRepos() {
			log.Info("repo:", repo.Name())
			if repo.Status.ReadOnly() {
				continue
			}
			if whitelist(repo.GoPath()) {
				log.Warn("skipping whitelist", repo.GoPath())
				continue
			}
			good, files := repo.Status.GitLsFiles()
			if !good {
				log.Warn("Something went wrong", repo.GoPath())
				continue
			}
			for _, filename := range strings.Split(files, "\n") {
				log.Info("\tfile", filename)
				if filename == "go.mod" {
					log.Info("Found go.mod. does version match release version?")
					log.Info(repo.Status.GetLastTagVersion(), "vs", repo.Status.GetTargetVersion())
					if repo.Status.GetLastTagVersion() != repo.Status.GetTargetVersion() {
						log.Info(repo.Status.GetLastTagVersion(), "vs", repo.Status.GetTargetVersion())
						log.Info("Found go.sum. version mismatch")
						setCurrentRepo(repo, "VERY BROKEN", "rewind go.mod commit")
						return
					}
				}
				if filename == "go.sum" {
					log.Info("Found go.sum. does version match release version?")
					log.Info(repo.Status.GetLastTagVersion(), "vs", repo.Status.GetTargetVersion())
					if repo.Status.GetLastTagVersion() != repo.Status.GetTargetVersion() {
						log.Info(repo.Status.GetLastTagVersion(), "vs", repo.Status.GetTargetVersion())
						log.Info("Found go.sum. version mismatch")
						setCurrentRepo(repo, "VERY BROKEN", "rewind go.mod commit")
						return
					}
				}
			}
		}
		log.Info("All repos seem okay")
	})
	grid.NextRow()

}

func buttonDisable() {
	me.Disable()
}

func buttonEnable() {
	me.Enable()
}

func setCurrentRepo(newcur *repolist.RepoRow, s string, note string) bool {
	if newcur.ReadOnly() {
		return false
	}

	me.release.repo.SetText(newcur.GoPath())
	me.release.status.SetText(s)
	me.release.notes.SetText(note)
	me.current = newcur
	me.release.version.SetText(me.current.Status.GetTargetVersion())
	me.release.releaseVersionB.SetText("release version " + me.current.Status.GetTargetVersion())
	me.release.openrepo.Enable()

	return true
}

// trys to figure out if there is still something to update
// todo: redo this logic as it is terrible
// rename this findNext()
func findNext() bool {
	for _, repo := range me.repos.View.AllRepos() {
		if repo.Status.IsReleased() {
			continue
		}
		if whitelist(repo.GoPath()) {
			continue
		}
		if repo.Status.Whitelist {
			continue
		}
		if repo.ReadOnly() {
			// log.Info("findNext() skipping readonly")
			continue
		}
		if repo.CheckDirty() {
			log.Info("findNext() skipping dirty")
			continue
		}
		// do makeredomod here
		// if ! repo.Status.Exists("go.sum") {
		// }
		if repo.Status.IsPrimitive() {
			log.Info("findNext()", repo.GoPath())
			if setCurrentRepo(repo, "PRIMATIVE", "release new version") {
				return true
			}
			continue
		}
		log.Info("findNext()", repo.GoPath(), "is not a primative repo")
		if checkValidGoSum(repo) {
			setCurrentRepo(repo, "should be good to release", "pretty sure")
			return true
		}
	}
	log.Info("tried to findNext() but not sure what to do next")
	me.release.status.SetText("ALL DONE?")
	return false
}