package main

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

	"go.wit.com/lib/protobuf/forgepb"
	"go.wit.com/lib/protobuf/gitpb"
	"go.wit.com/log"
)

// This will recreate your go.sum and go.mod files

// checks to see if every 'master' git branch version
// matches the go.sum file
func cleanGoDepsCheckOk(check *gitpb.Repo) error {
	var err error = nil
	var fixes [][]string
	log.Printf("current repo %s go dependancy count: %d", check.GetGoPath(), check.GoDepsLen())
	if check.GoDeps == nil {
		return errors.New("check.GoDeps == nil")
	}
	all := check.GoDeps.SortByGoPath()
	for all.Scan() {
		depRepo := all.Next()
		found := forge.FindByGoPath(depRepo.GetGoPath())
		if found == nil {
			if forge.CheckOverride(depRepo.GetGoPath()) {
				// skip this gopath because it's probably broken forever
				continue
			}
			log.Info("not found:", depRepo.GetGoPath())
			err = errors.New("not found: " + depRepo.GetGoPath())
			continue
		}
		// log.Info("found dep", depRepo.GetGoPath())
		if depRepo.GetVersion() != found.GetMasterVersion() {
			check := forge.FindByGoPath(depRepo.GetGoPath())
			var ends string
			if check.CheckDirty() {
				ends = "(dirty) "
			}

			if forge.Config.IsReadOnly(check.GetGoPath()) {
				ends += "(ignoring read-only) "
				if argv.Verbose {
					log.Printf("%-48s  ok error .%s. vs .%s. %s", depRepo.GetGoPath(),
						depRepo.GetVersion(), found.GetMasterVersion(), ends)
				}
			} else {
				if forge.CheckOverride(depRepo.GetGoPath()) {
					ends += "(override) "
					if argv.Verbose {
						log.Printf("%-48s  ok error .%s. vs .%s. %s", depRepo.GetGoPath(),
							depRepo.GetVersion(), found.GetMasterVersion(), ends)
						// skip this gopath because it's probably broken forever
					}
					continue
				} else {
					log.Printf("%-48s     error %10s vs %10s %s", depRepo.GetGoPath(),
						depRepo.GetVersion(), found.GetMasterVersion(), ends)
					errs := fmt.Sprintf("%s error %s vs %s %s", depRepo.GetGoPath(),
						depRepo.GetVersion(), found.GetMasterVersion(), ends)
					if ok, _ := forgepb.ValidGoVersion(found.GetMasterVersion()); ok {
						// can't go get invalid version numbers
						cmd := []string{"go", "get", depRepo.GetGoPath() + "@" + found.GetMasterVersion()}
						fixes = append(fixes, cmd)
					}
					err = errors.New(errs)
				}
			}
		}
	}
	for i, cmd := range fixes {
		log.Info("try cmd", i, cmd)
		check.RunRealtime(cmd)
	}
	return err
}

func trimGoSum(check *gitpb.Repo) error {
	var stuff map[string]string
	stuff = make(map[string]string)

	var modver map[string]string
	modver = make(map[string]string)

	var good map[string]bool
	good = make(map[string]bool)

	if check == nil {
		log.Info("boo, check == nil")
		return errors.New("*repo == nil")
	}
	filename := filepath.Join(filepath.Join(check.FullPath, "go.sum"))
	data, err := os.ReadFile(filename)
	if err != nil {
		return err
	}

	for _, line := range strings.Split(string(data), "\n") {
		parts := strings.Fields(line)
		if len(parts) < 3 {
			log.Info("WIERD OR BAD:", line)
			continue
		}

		gopath := parts[0]
		version := parts[1]
		hash := parts[2]

		if strings.HasSuffix(version, "/go.mod") {
			if _, ok := stuff[gopath]; ok {
				if argv.Verbose {
					log.Info("MATCHED: gopath:", gopath, "version:", version)
				}
				modver[gopath] = version + " " + hash
				good[gopath] = true
			} else {
				if argv.Verbose {
					log.Info("GARBAGE: gopath:", gopath, "version:", version)
				}
			}
		} else {
			if argv.Verbose {
				log.Info("GOOD   : gopath:", gopath, "version:", version)
			}
			stuff[gopath] = version + " " + hash
		}
	}

	keys := make([]string, 0, len(stuff))
	for k := range stuff {
		keys = append(keys, k)
	}

	// rewrite the go.sum file
	newfilename := filepath.Join(filepath.Join(check.FullPath, "go.sum"))
	newf, err := os.OpenFile(newfilename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer newf.Close()
	sort.Strings(keys)
	for _, gopath := range keys {
		if good[gopath] {
			fmt.Fprintf(newf, "%s %s\n", gopath, stuff[gopath])
			fmt.Fprintf(newf, "%s %s\n", gopath, modver[gopath])
			check := forge.FindByGoPath(gopath)
			if check == nil {
				log.Info("gopath does not really exist:", gopath)
			}
		}
	}
	// fmt.Fprintln(newf, "test")
	return nil
}