package main

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

	"go.wit.com/dev/alexflint/arg"
	"go.wit.com/gui"
	"go.wit.com/lib/gui/repolist"
	"go.wit.com/lib/gui/repostatus"
	"go.wit.com/lib/gui/shell"
	"go.wit.com/log"
)

var Version string

var rv *repolist.RepoList
var myargs args

func main() {
	pp := arg.MustParse(&myargs)

	if myargs.Repo == "" {
		pp.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	if myargs.Repo == "version" {
		log.Info(Version)
		os.Exit(0)
	}

	if myargs.Repo == "version" || myargs.Repo == "help" || myargs.Repo == "?" {
		pp.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	// figures out where you're go.work file is
	wdir, err := findWorkFile()
	if err != nil {
		log.Info(err)
		os.Exit(-1)
	}
	log.Info("scanning directory:", wdir)
	os.Setenv("REPO_WORK_PATH", wdir)

	// readControlFile()

	b := gui.RawBox()
	rv = repolist.AutotypistView(b)

	os.Setenv("REPO_AUTO_CLONE", "true")
	newr, err := rv.NewRepo(myargs.Repo)
	if err != nil {
		log.Info("could not download:", err)
		os.Exit(-1)
	}
	newr.Status.MakeRedomod()

	// rv.NewRepo("go.wit.com/apps/helloworld")
	for _, path := range repostatus.ScanGitDirectories(wdir) {
		gopath := strings.TrimPrefix(path, wdir)
		gopath = strings.Trim(gopath, "/")
		// log.Info("Also should add:", gopath)
		rv.NewRepo(gopath)
	}

	godep := newr.Status.GetGoDeps()
	if myargs.Recursive {
		for gopath, version := range godep {
			repo, err := rv.NewRepo(gopath)
			if err != nil {
				log.Info("git clone failed for", gopath, version)
				continue
			}
			repo.Status.MakeRedomod()
		}
	}

	var count int
	for _, repo := range rv.AllRepos() {
		count += 1
		if !repo.Status.Exists("go.mod") {
			repo.Status.MakeRedomod()
		}
	}

	log.Info("Total repositories:", count)
	log.Info("Finished go-clone for", myargs.Repo)
	if !myargs.NoWork {
		log.Info("Creating", wdir+"/go.work")
		rv.MakeGoWork()
		shell.RunPath(wdir, []string{"go", "work", "use"})
	}

	/*
		for _, repo := range rv.AllRepos() {
			log.Info("found repo", repo.GoPath(), repo.Status.Path())
		}
	*/
}

// look for or make a go.work file
// otherwise use ~/go/src
func findWorkFile() (string, error) {
	if myargs.GoSrc {
		// user put --go-src on the command line so use ~/go/src
		return useGoSrc()
	}

	pwd, err := os.Getwd()
	if err == nil {
		// Check for go.work in the current directory and then move up until root
		if pwd, err := digup(pwd); err == nil {
			// found an existing go.work file
			os.Chdir(pwd)
			return pwd, nil
		}

		// if the user added '--work' on the cmdline, make a work directory and init the go.work file
		if ! myargs.NoWork {
			pwd, err = os.Getwd()
			newpwd := filepath.Join(pwd, "work")
			shell.Mkdir(newpwd)
			os.Chdir(newpwd)
			if _, err := os.Stat("go.work"); err == nil {
				return newpwd, nil
			}
			shell.RunPath(newpwd, []string{"go", "work", "init"})
			if shell.Exists("go.work") {
				return newpwd, nil
			}
		}
	}

	// there are no go.work files, resume the ~/go/src behavior from prior to golang 1.22
	return useGoSrc()
}

// this is the 'old way" and works fine for me. I use it because I like the ~/go/src directory
// because I know exactly what is in it: GO stuff & nothing else
func useGoSrc() (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}
	pwd := filepath.Join(homeDir, "go/src")
	shell.Mkdir(pwd)
	os.Chdir(pwd)
	return pwd, nil
}

func digup(path string) (string, error) {
	for {
		workFilePath := filepath.Join(path, "go.work")
		if _, err := os.Stat(workFilePath); err == nil {
			return path, nil // Found the go.work file
		} else if !os.IsNotExist(err) {
			return "", err // An error other than not existing
		}

		parentPath := filepath.Dir(path)
		if parentPath == path {
			break // Reached the filesystem root
		}
		path = parentPath
	}

	return "", fmt.Errorf("no go.work file found")
}