package sync

import (
	"fmt"
	"time"

	"git.csclub.uwaterloo.ca/public/merlin/config"
)

// Start sync job for the repo if more than repo.Frequency seconds have elapsed since its last job
// and is not currently running. Returns true iff a job is started.
func SyncIfPossible(repo *config.Repo, force bool) bool {
	if repo.State.IsRunning {
		return false
	}

	curTime := time.Now().Unix()
	if force || curTime-repo.State.LastAttemptStartTime > int64(repo.Frequency) {
		repo.State.IsRunning = true
		repo.State.LastAttemptStartTime = curTime
		repo.SaveState()
		repo.Logger.Info(fmt.Sprintf("Repo %s has started syncing", repo.Name))

		go startRepoSync(repo, force)
		return true
	}
	return false
}

// Called after a repo completes a sync. Update the repo's status using the current time and the exit code.
func SyncCompleted(repo *config.Repo, exit int) {
	repoState := repo.State

	syncTook := time.Now().Unix() - repoState.LastAttemptStartTime
	nextSync := repo.Frequency - int(syncTook)
	if nextSync < 0 {
		nextSync = 0
	}
	repoState.IsRunning = false
	repoState.LastAttemptExit = exit
	repoState.LastAttemptRunTime = syncTook
	repo.SaveState()

	exitStr := config.StatusToString(exit)
	repo.Logger.Info(fmt.Sprintf("Sync %s after running for %d seconds, will run again in %d seconds", exitStr, syncTook, nextSync))

	go postRepoSync(repo, exit)
}

// begin and manage the steps of the sync and return the exit status
func startRepoSync(repo *config.Repo, force bool) {
	status := config.FAILURE
	done := false

	defer func() {
		repo.DoneChan <- config.SyncResult{
			Name: repo.Name,
			Exit: status,
		}
	}()

	status, done = preRepoSync(repo)
	if done && !force {
		return
	}

	status = runRepoSync(repo)
}
