package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

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

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

var lw *gadgets.BasicWindow

var allsections []*section

type witRepo struct {
	sec       *section
	path      *gui.Node
	downloadB *gui.Node
}

type section struct {
	name   string
	hidden bool

	parent       *gui.Node
	box          *gui.Node
	group        *gui.Node
	grid         *gui.Node // where the repos are listed
	hideCB       *gui.Node
	downloadAllB *gui.Node
	witRepos     []*witRepo
}

func listWindow() *gadgets.BasicWindow {
	if lw != nil {
		lw.Toggle()
		return lw
	}
	lw = gadgets.NewBasicWindow(me.myGui, "go.wit.com repositories")
	lw.Custom = func() {
		log.Warn("got to close")
	}

	lw.Make()
	lw.StandardClose()
	lw.Draw()
	box := lw.Box()
	group := box.NewGroup("list")
	group.NewButton("make new go version list", func() {
		dumpVersions()
	})

	var lines []string
	var curs *section

	lines = dumpURL("https://go.wit.com/list")
	for i, line := range lines {
		if line == "" {
			continue
		}
		if line[0] == '#' {
			curs = NewSection(group, line)
			log.Warn("new group:", line)
			continue
		}
		log.Warn(i, line)
		parts := strings.Split(line, " ")
		if curs != nil {
			curs.add(parts[0])
		}
	}
	for i, sec := range allsections {
		log.Info("section name:", sec.name, "hidden:", sec.hidden, i)
		parts := strings.Split(sec.name, " ")
		if len(parts) > 1 {
			if parts[1] != "Applications" {
				sec.Hide()
			}
		}
	}
	// lw.Toggle()
	return lw
}

func downloadRepo(path string) bool {
	log.Info("downloading", path, "here")
	os.Setenv("GO111MODULE", "off")

	goSrcDir := me.goSrcPwd.String()
	if !quickCmd(goSrcDir, []string{"go", "get", "-v", path}) {
		log.Info("go get failed")
		return false
	}

	fullpath := filepath.Join(goSrcDir, path)
	if !quickCmd(fullpath, []string{"go", "get", "-v", "-u", "."}) {
		log.Info("go get depends failed")
		return false
	}
	if me.autoDryRun.Checked() {
		return false
	}
	return true
}

func (r *witRepo) doDownload() bool {
	if me.autoDryRun.Checked() {
		r.downloadB.SetLabel("uncheck --dry-run")
		return false
	}
	if r.downloadB.String() == "downloaded" {
		log.Info("skipping already downloaded", r.path.String())
		return true
	}
	if downloadRepo(r.path.String()) {
		log.Info("download", r.path.String(), "worked")
		r.downloadB.SetLabel("downloaded")
		r.downloadB.Disable()
	} else {
		r.downloadB.SetLabel("failed")
		log.Info("download", r.path.String(), "failed")
		return false
	}
	return true
}

func (s *section) add(path string) {
	if s == nil {
		return
	}
	tmp := new(witRepo)
	tmp.sec = s
	tmp.path = s.grid.NewLabel(path)
	tmp.downloadB = s.grid.NewButton("download", func() {
		lw.Disable()
		tmp.doDownload()
		lw.Enable()
	})
	if repostatus.VerifyLocalGoRepo(path) {
		log.Verbose("newRepo actually exists", path)
		tmp.downloadB.SetLabel("downloaded")
		tmp.downloadB.Disable()
	}

	s.witRepos = append(s.witRepos, tmp)
}

func NewSection(parent *gui.Node, desc string) *section {
	news := new(section)
	news.name = desc
	news.parent = parent
	news.box = news.parent.NewBox("bw vbox", true)
	news.group = news.box.NewGroup(desc)
	news.hideCB = news.box.NewCheckbox("hide")
	news.hideCB.Custom = func() {
		news.toggle()
	}
	news.downloadAllB = news.box.NewButton("download all", func() {
		lw.Disable()
		log.Warn("Download all here")
		for i, wrepo := range news.witRepos {
			log.Warn("download:", i, wrepo.path.String())
			wrepo.doDownload()
			//wrepo.path.Show()
			//wrepo.downloadB.Show()
		}
		lw.Enable()
	})
	news.grid = news.parent.NewGrid("sections", 2, 1)
	allsections = append(allsections, news)
	return news
}

func (s *section) toggle() {
	log.Warn(s.name)
	if s.hidden {
		s.hidden = false
		for i, wrepo := range s.witRepos {
			log.Warn(i, wrepo.path.String())
			wrepo.path.Show()
			wrepo.downloadB.Show()
		}
	} else {
		s.Hide()
	}
}

func (s *section) Hide() {
	s.hidden = true
	s.hideCB.SetChecked(true)
	for i, wrepo := range s.witRepos {
		log.Warn(i, wrepo.path.String())
		wrepo.path.Hide()
		wrepo.downloadB.Hide()
	}
}

/*
func dumpURL(url string) string {
	resp, err := http.Get(url)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()

	return resp.Body.String()

		_, err = io.Copy(os.Stdout, resp.Body)
		if err != nil {
			return ""
		}
}
*/

func dumpURL(url string) []string {
	resp, err := http.Get(url)
	if err != nil {
		return nil
	}
	defer resp.Body.Close()

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil
	}

	return strings.Split(string(bodyBytes), "\n")
}

func dumpVersions() {
	f, _ := os.OpenFile("/tmp/go.wit.com.versions", os.O_WRONLY|os.O_CREATE, 0600)
	defer f.Close()
	for _, sec := range allsections {
		for _, wrepo := range sec.witRepos {
			r, ok := me.allrepos[wrepo.path.String()]
			if ok {
				_, out := r.status.RunCmd([]string{"git", "log", "-1", "--format=%at", r.lastTag.String()})
				out = strings.TrimSpace(out)

				// Convert the string to an integer
				gitTagTimestampInt, err := strconv.ParseInt(out, 10, 64)
				if err != nil {
					fmt.Println("Error converting timestamp:", err)
					return
				}

				// Parse the Unix timestamp into a time.Time object
				gitTagDate := time.Unix(gitTagTimestampInt, 0)

				// Get the current time
				currentTime := time.Now()

				// Calculate the duration between the git tag date and the current time
				duration := currentTime.Sub(gitTagDate)

				// s := fmt.Sprint(duration)
				// fmt.Println("Duration since the git tag date:", s)

				// fmt.Println("Default formatting:", duration.String())
				// fmt.Println("Custom formatting:", formatDuration(duration))
				log.Warn("found:", wrepo.path.String(), r.lastTag.String(), out, formatDuration(duration))
				fmt.Fprintln(f, wrepo.path.String(), r.lastTag.String(), out)
			}
			//wrepo.path.Show()
		}
	}
}

func formatDuration(d time.Duration) string {
	seconds := int(d.Seconds()) % 60
	minutes := int(d.Minutes()) % 60
	hours := int(d.Hours()) % 24
	days := int(d.Hours()) / 24

	result := ""
	if days > 0 {
		result += fmt.Sprintf("%dd ", days)
		return result
	}
	if hours > 0 {
		result += fmt.Sprintf("%dh ", hours)
		return result
	}
	if minutes > 0 {
		result += fmt.Sprintf("%dm ", minutes)
		return result
	}
	if seconds > 0 {
		result += fmt.Sprintf("%ds", seconds)
	}
	return result
}