package backend

import (
	"context"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// A component to check for updates from the
// Github releases/latest URL.
type UpdateChecker struct {
	OnUpdatedVersionFound func()

	versionTagFound  string
	latestReleaseURL string
	appVersionTag    string
	lastCheckedTag   *string
}

func NewUpdateChecker(appVersionTag, latestReleaseURL string, lastCheckedTag *string) UpdateChecker {
	return UpdateChecker{
		appVersionTag:    appVersionTag,
		latestReleaseURL: latestReleaseURL,
		lastCheckedTag:   lastCheckedTag,
	}
}

// Start automatically polling for updates in the background.
// Quits when the given ctx's Done channel returns a value.
func (u *UpdateChecker) Start(ctx context.Context, interval time.Duration) {
	go func() {
		u.checkForUpdate() // check once at startup
		t := time.NewTicker(interval)
		for {
			select {
			case <-ctx.Done():
				t.Stop()
				return
			case <-t.C:
				u.checkForUpdate()
			}
		}
	}()
}

func (u *UpdateChecker) VersionTagFound() string {
	return u.versionTagFound
}

func (u *UpdateChecker) LatestReleaseURL() *url.URL {
	url, _ := url.Parse(u.latestReleaseURL)
	return url
}

func (u *UpdateChecker) checkForUpdate() {
	t := u.CheckLatestVersionTag()
	if t != "" && t != *u.lastCheckedTag {
		u.versionTagFound = t
		if u.OnUpdatedVersionFound != nil {
			u.OnUpdatedVersionFound()
		}
	}
}

func (u *UpdateChecker) CheckLatestVersionTag() string {
	resp, err := http.Head(u.latestReleaseURL)
	if err != nil {
		log.Printf("failed to check for newest version: %s", err.Error())
		return ""
	}
	url := resp.Request.URL.String()
	url = strings.TrimSuffix(url, "/")
	idx := strings.LastIndex(url, "/")
	if idx >= len(url)-1 {
		return ""
	}
	return url[idx+1:]
}
