package whitesource

import (
	"fmt"
	"github.com/SAP/jenkins-library/pkg/log"
	"time"
)

type whitesourcePoller interface {
	GetProjectByToken(projectToken string) (Project, error)
}

// BlockUntilReportsAreReady polls the WhiteSource system for all projects known to the Scan and blocks
// until their LastUpdateDate time stamp is from within the last 20 seconds.
func (s *Scan) BlockUntilReportsAreReady(sys whitesourcePoller) error {
	for _, project := range s.ScannedProjects() {
		if err := pollProjectStatus(project.Token, s.ScanTime(project.Name), sys); err != nil {
			return err
		}
	}
	return nil
}

type pollOptions struct {
	scanTime         time.Time
	maxAge           time.Duration
	timeBetweenPolls time.Duration
	maxWaitTime      time.Duration
}

// pollProjectStatus polls project LastUpdateDate until it reflects the most recent scan
func pollProjectStatus(projectToken string, scanTime time.Time, sys whitesourcePoller) error {
	options := pollOptions{
		scanTime:         scanTime,
		maxAge:           20 * time.Second,
		timeBetweenPolls: 20 * time.Second,
		maxWaitTime:      30 * time.Minute,
	}
	return blockUntilProjectIsUpdated(projectToken, sys, options)
}

// blockUntilProjectIsUpdated polls the project LastUpdateDate until it is newer than the given time stamp
// or no older than maxAge relative to the given time stamp.
func blockUntilProjectIsUpdated(projectToken string, sys whitesourcePoller, options pollOptions) error {
	startTime := time.Now()
	for {
		project, err := sys.GetProjectByToken(projectToken)
		if err != nil {
			return err
		}

		if project.LastUpdateDate == "" {
			log.Entry().Infof("last updated time missing from project metadata, retrying")
		} else {
			lastUpdatedTime, err := time.Parse(DateTimeLayout, project.LastUpdateDate)
			if err != nil {
				return fmt.Errorf("failed to parse last updated time (%s) of Whitesource project: %w",
					project.LastUpdateDate, err)
			}
			age := options.scanTime.Sub(lastUpdatedTime)
			if age < options.maxAge {
				//done polling
				break
			}
			log.Entry().Infof("time since project was last updated %v > %v, polling status...", age, options.maxAge)
		}

		if time.Now().Sub(startTime) > options.maxWaitTime {
			return fmt.Errorf("timeout while waiting for Whitesource scan results to be reflected in service")
		}

		time.Sleep(options.timeBetweenPolls)
	}
	return nil
}
