package main

import (
	"os"

	"go.wit.com/lib/gadgets"
	"go.wit.com/lib/gui/repolist"
	"go.wit.com/lib/protobuf/forgepb"
	"go.wit.com/lib/protobuf/gitpb"
	"go.wit.com/log"

	"go.wit.com/gui"
)

type repoWindow struct {
	win *gadgets.BasicWindow
	box *gui.Node

	// the top box of the repolist window
	topbox *gui.Node

	View *repolist.RepoList
}

func (r *repoWindow) Hidden() bool {
	return r.win.Hidden()
}

func (r *repoWindow) Show() {
	r.win.Show()
}

func (r *repoWindow) Hide() {
	r.win.Hide()
}

func (r *repoWindow) Disable() {
	r.box.Disable()
}

func (r *repoWindow) Enable() {
	r.box.Enable()
}

// you can only have one of these
func makeRepoView() *repoWindow {
	if me.repos != nil {
		return me.repos
	}
	r := new(repoWindow)
	r.win = gadgets.RawBasicWindow("All git repositories in ~/go/src/")
	r.win.Make()

	r.box = r.win.Box().NewBox("bw vbox", false)
	// me.reposwin.Draw()
	r.win.Custom = func() {
		log.Warn("Repo Window close. hidden=true")
		// sets the hidden flag to false so Toggle() works
		r.win.Hide()
	}

	r.topbox = r.repoMenu()

	r.View = repolist.InitBox(me.forge, r.box)
	r.View.Enable()

	r.View.ScanRepositories()
	return r
}

func (r *repoWindow) reInitForge() {
	// re-read everything
	me.forge = forgepb.Init()
	me.found = new(gitpb.Repos)
	me.repos = makeRepoView()
	me.repos.Show()

	// update the protobuf pointers
	loop := me.forge.Repos.All()
	for loop.Scan() {
		repo := loop.Next()
		vrepo := me.repos.View.FindByPath(repo.GetGoPath())
		if vrepo != nil {
			vrepo.UpdatePb(repo)
		}
	}

	// now update the gui
	vloop := me.repos.View.ReposSortByName()
	for vloop.Scan() {
		var repo *repolist.RepoRow
		repo = vloop.Repo()
		repo.NewScan()
	}

	i, s := me.repos.View.ScanRepositories()
	log.Info("re-scanning done", i, "repos in", s)
}

func (r *repoWindow) repoMenu() *gui.Node {
	// reposbox.SetExpand(false)
	group1 := r.box.NewGroup("Filter:")

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

	box2 := hbox.Box().Horizontal()
	/*
	 */

	dirty := box2.NewCheckbox("dirty")
	dirty.Custom = func() {
		log.Info("filter dirty =", dirty.Checked())
	}

	box2.NewButton("merge user to devel", func() {
		r.Disable()
		defer r.Enable()
		if IsAnythingDirty() {
			log.Info("You can't apply patches when repos are dirty")
			me.forge.PrintHumanTable(me.found)
			return
		}
		if !r.mergeAllUserToDevel() {
			return
		}
	})

	box2.NewButton("test master merge", func() {
		r.Disable()
		r.mergeAllDevelToMain()
		// r.reInitForge()
		r.Enable()
	})

	box2.NewButton("show apps", func() {
		loop := me.repos.View.ReposSortByName()
		for loop.Scan() {
			var repo *repolist.RepoRow
			repo = loop.Repo()
			if repo.IsBinary() {
				// log.Info(repo.Status.Path(), "compile here. Show()")
				repo.Show()
			} else {
				// log.Info(repo.Status.Path(), "library here. Hide()")
				repo.Hide()
			}
		}
	})
	box2.NewButton("re-init forge", func() {
		log.Info("re-scanning now")
		r.reInitForge()
	})
	box2.NewButton("ConfigSave()", func() {
		me.forge.ConfigSave()
	})
	box2.NewButton("Table()", func() {
		me.found = new(gitpb.Repos)
		loop := me.forge.Repos.All()
		for loop.Scan() {
			repo := loop.Next()
			me.found.AppendByGoPath(repo)
		}
		me.forge.PrintHumanTable(me.found)
	})
	box2.NewButton("Prep for release()", func() {
		r.Disable()
		defer r.Enable()
		if IsAnythingDirty() {
			log.Info("You can't apply patches when repos are dirty")
			me.forge.PrintHumanTable(me.found)
			return
		}
		if !r.mergeAllUserToDevel() {
			return
		}
		if !r.mergeAllDevelToMain() {
			return
		}
		doAllCheckoutMaster()
		os.Exit(0)

	})

	return box2
}

func (r *repoWindow) mergeAllDevelToMain() bool {
	var count int
	log.Info("merge all here")
	loop := me.forge.Repos.All()
	for loop.Scan() {
		repo := loop.Next()
		if me.forge.Config.IsReadOnly(repo.GetGoPath()) {
			log.Info("skipping readonly", repo.GetFullPath())
			continue
		}
		if repo.IsDirty() {
			log.Info("skipping dirty", repo.GetFullPath())
			continue
		}
		if repo.GetDevelVersion() != repo.GetUserVersion() {
			log.Info("devel and user branch are different", repo.GetFullPath())
			continue
		}
		if repo.GetDevelVersion() == repo.GetMasterVersion() {
			log.Info("devel and master branch are the same", repo.GetFullPath())
			continue
		}
		count += 1
		if result, err := repo.MergeDevelToMaster(); err == nil {
			log.Warn("MERGE WORKED", repo.GetFullPath())
			repo.Reload()
			vrepo := me.repos.View.FindByPath(repo.GetGoPath())
			if vrepo != nil {
				vrepo.UpdatePb(repo)
				vrepo.NewScan()
			}
			me.forge.SetConfigSave(true)
			// continue
			continue
		} else {
			log.Warn("THINGS FAILED ", repo.GetFullPath())
			log.Warn("err", err)
			for _, line := range result.Stdout {
				log.Warn("stdout:", line)
			}
			for _, line := range result.Stderr {
				log.Warn("stderr:", line)
			}
			return false
		}
	}
	log.Warn("EVERYTHING WORKED count =", count)
	return true
}

func (r *repoWindow) mergeAllUserToDevel() bool {
	log.Info("merge all here")
	loop := me.forge.Repos.All()
	for loop.Scan() {
		repo := loop.Next()
		if me.forge.Config.IsReadOnly(repo.GetGoPath()) {
			// log.Info("skipping readonly", repo.GetFullPath())
			continue
		}
		if repo.IsDirty() {
			log.Info("skipping dirty", repo.GetFullPath())
			continue
		}
		if repo.GetCurrentBranchName() != repo.GetUserBranchName() {
			log.Info("not on user branch", repo.GetFullPath())
			continue
		}
		if repo.GetDevelVersion() == repo.GetUserVersion() {
			log.Info("devel and user branch are the same", repo.GetFullPath())
			continue
		}
		if result, err := repo.MergeUserToDevel(); err == nil {
			log.Warn("THINGS SEEM OK", repo.GetFullPath())
			repo.Reload()
			vrepo := me.repos.View.FindByPath(repo.GetGoPath())
			if vrepo != nil {
				vrepo.UpdatePb(repo)
				vrepo.NewScan()
			}
			me.forge.SetConfigSave(true)
			continue
		} else {
			log.Warn("THINGS FAILED ", repo.GetFullPath())
			log.Warn("err", err)
			for _, line := range result.Stdout {
				log.Warn("stdout:", line)
			}
			for _, line := range result.Stderr {
				log.Warn("stderr:", line)
			}
			return false
		}
	}
	log.Warn("EVERYTHING WORKED")
	return true
}