// This is a simple example
package main

import (
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"go.wit.com/gui"
	"go.wit.com/lib/gadgets"
	"go.wit.com/lib/gui/repostatus"
	"go.wit.com/log"
)

func (r *repo) String() string {
	return r.status.String()
}

func (r *repo) getPath() string {
	return r.path
}

func RemoveFirstElement(slice []string) (string, []string) {
	if len(slice) == 0 {
		return "", slice // Return the original slice if it's empty
	}
	return slice[0], slice[1:] // Return the slice without the first element
}

// returns path, master branch name, devel branch name, user branch name
func splitLine(line string) (string, string, string, string) {
	var path, master, devel, user string
	parts := strings.Split(line, " ")
	path, parts = RemoveFirstElement(parts)
	master, parts = RemoveFirstElement(parts)
	devel, parts = RemoveFirstElement(parts)
	user, parts = RemoveFirstElement(parts)
	// path, master, devel, user := strings.Split(line, " ")
	return path, master, devel, user
}

func myrepolist() []string {
	homeDir, _ := os.UserHomeDir()
	cfgfile := filepath.Join(homeDir, ".config/myrepolist")
	content, _ := ioutil.ReadFile(cfgfile)
	out := string(content)
	out = strings.TrimSpace(out)
	lines := strings.Split(out, "\n")
	return lines
}

func (r *repo) Hide() {
	r.pLabel.Hide()
	r.lastTag.Hide()
	r.vLabel.Hide()

	r.masterVersion.Hide()
	r.develVersion.Hide()
	r.userVersion.Hide()

	r.dirtyLabel.Hide()
	r.statusButton.Hide()
	r.hidden = true
}

func (r *repo) Show() {
	r.pLabel.Show()
	r.lastTag.Show()
	r.vLabel.Show()

	r.masterVersion.Show()
	r.develVersion.Show()
	r.userVersion.Show()

	r.dirtyLabel.Show()
	r.statusButton.Show()
	r.hidden = false
}

func addRepo(grid *gui.Node, path string, master string, devel string, user string) {
	_, ok := me.allrepos[path]
	if ok {
		log.Info("addRepo() already had path", path)
		return
	}

	newRepo := new(repo)

	path = strings.Trim(path, "/") // trim any extranous '/' chars put in the config file by the user
	if path == "" {
		log.Warn("addRepo() got empty path", path, master, devel, user)
		return
	}

	if repostatus.VerifyLocalGoRepo(path) {
		log.Verbose("newRepo actually exists", newRepo.getPath())
	} else {
		log.Warn("repostatus.VerifyLocalGoRepo() failed for for", path, master, devel, user)
		return
	}

	newRepo.path = path
	newRepo.pLabel = grid.NewLabel(path).SetProgName("path")

	newRepo.lastTag = grid.NewLabel("").SetProgName("lastTag")

	newRepo.masterVersion = grid.NewLabel("").SetProgName("masterVersion")
	newRepo.develVersion = grid.NewLabel("").SetProgName("develVersion")
	newRepo.userVersion = grid.NewLabel("").SetProgName("userVersion")

	newRepo.dirtyLabel = grid.NewLabel("")

	newRepo.vLabel = grid.NewLabel("").SetProgName("current")

	newRepo.statusButton = grid.NewButton("Configure", func() {
		if newRepo.status == nil {
			log.Warn("status window doesn't exist")
			return
		}
		log.Warn("status window exists. trying TestDraw() here")
		newRepo.status.Toggle()
	})

	newRepo.status = repostatus.NewRepoStatusWindow(newRepo.path)
	newRepo.hidden = false
	newRepo.status.SetMainWorkingName(master)
	newRepo.status.SetDevelWorkingName(devel)
	newRepo.status.SetUserWorkingName(user)

	me.allrepos[path] = newRepo
}

// This creates a window
func repolistWindow() {
	reposwin = gadgets.NewBasicWindow(me.myGui, "All git repositories in ~/go/src/")
	reposwin.Make()

	reposbox = reposwin.Box().NewBox("bw vbox", false)
	reposwin.Draw()
	reposwin.Custom = func() {
		log.Warn("GOT HERE: main() gadgets.NewBasicWindow() close")
		log.Warn("Should I do something special here?")
	}

	repoAllButtons(reposbox)

	reposgroup = reposbox.NewGroup("go repositories (read from ~/.config/myrepolist)")
	reposgrid = reposgroup.NewGrid("test", 8, 1)

	reposgrid.NewLabel("") // path goes here

	reposgrid.NewLabel("last tag").SetProgName("last tag")

	reposgrid.NewLabel("master version")
	reposgrid.NewLabel("devel version")
	reposgrid.NewLabel("user version")

	reposgrid.NewLabel("Status")

	reposgrid.NewLabel("Current Version").SetProgName("Current Version")

	reposgrid.NewLabel("Show()")

	usr, _ := user.Current()

	repos := myrepolist()
	for _, line := range repos {
		log.Verbose("repo =", line)
		path, mbranch, dbranch, ubranch := splitLine(line)
		if mbranch == "" {
			mbranch = "master"
		}
		if dbranch == "" {
			dbranch = "devel"
		}
		if ubranch == "" {
			ubranch = usr.Username
		}
		addRepo(reposgrid, path, mbranch, dbranch, ubranch)
	}

	// TODO: figure out why this borks everything
	/*
		for i, path := range repostatus.ListGitDirectories() {
			// log.Info("addRepo()", i, path)
			tmp := strings.TrimPrefix(path, me.goSrcPwd.String())
			log.Info("addRepo()", i, tmp)
			addRepo(reposgrid, tmp, "guimaster", "guidevel", usr.Username)
		}
	*/

	reposwin.Toggle()
}

func repoAllButtons(box *gui.Node) {
	// reposbox.SetExpand(false)
	group1 := box.NewGroup("Run on all repos:")

	hbox := group1.Box()
	// hbox.Horizontal()
	hbox.Vertical()

	box1 := hbox.Box().Vertical()
	box1.NewButton("status.Update() all", func() {
		for _, repo := range me.allrepos {
			repo.status.Update()
			repo.newScan()
		}
	})

	box2 := hbox.Box().Vertical()
	box2.NewButton("merge all user to devel", func() {
		reposwin.Disable()
		if !mergeAllUserToDevel() {
			return
		}
		reposwin.Enable()
	})

	box2.NewButton("merge all devel to main", func() {
		reposwin.Disable()
		if !mergeAllDevelToMain() {
			return
		}
		reposwin.Enable()
	})

	box2.NewButton("merge it all", func() {
		reposwin.Disable()
		if !mergeAllUserToDevel() {
			return
		}
		if !mergeAllDevelToMain() {
			return
		}
		reposwin.Enable()
	})

}

func mergeAllDevelToMain() bool {
	log.Info("merge all here")
	for _, repo := range me.allrepos {
		if repo.status.ReadOnly() {
			log.Info("skipping readonly", repo.String(), repo.dirtyLabel.String())
			continue
		}
		if repo.dirtyLabel.String() != "merge to main" {
			log.Info("skipping. not merge to main", repo.String(), repo.dirtyLabel.String())
			continue
		}
		if repo.status.CheckDirty() {
			log.Info("skipping dirty", repo.String(), repo.dirtyLabel.String())
			continue
		}
		log.Info("found", repo.String(), repo.dirtyLabel.String())
		// repo.status.Update()
		if repo.status.RunDevelMergeB() {
			log.Warn("THINGS SEEM OK fullAutomation() returned true.")
		} else {
			log.Warn("THINGS FAILED fullAutomation() returned false")
			return false
		}
		repo.status.Update()
		repo.newScan()
	}
	log.Warn("EVERYTHING WORKED")
	return true
}

func mergeAllUserToDevel() bool {
	log.Info("merge all here")
	for _, repo := range me.allrepos {
		if repo.status.ReadOnly() {
			log.Info("skipping readonly", repo.String(), repo.dirtyLabel.String())
			continue
		}
		if repo.dirtyLabel.String() != "merge to devel" {
			log.Info("skipping. not merge to devel", repo.String(), repo.dirtyLabel.String())
			continue
		}
		if repo.status.CheckDirty() {
			log.Info("skipping dirty", repo.String(), repo.dirtyLabel.String())
			continue
		}
		log.Info("found", repo.String(), repo.dirtyLabel.String())
		// repo.status.Update()
		if repo.status.RunDevelMergeB() {
			log.Warn("THINGS SEEM OK fullAutomation() returned true.")
		} else {
			log.Warn("THINGS FAILED fullAutomation() returned false")
			return false
		}
		repo.status.Update()
		repo.newScan()
	}
	log.Warn("EVERYTHING WORKED")
	return true
}