package measurex

//
// Logger
//
// Code for logging
//

import (
	"fmt"
	"sync"
	"time"

	"github.com/ooni/probe-cli/v3/internal/netxlite"
)

// Logger is the logger type we use. This type is compatible
// with the logger type of github.com/apex/log.
type Logger interface {
	netxlite.Logger

	Info(msg string)
	Infof(format string, v ...interface{})

	Warn(msg string)
	Warnf(format string, v ...interface{})
}

// NewOperationLogger creates a new logger that logs
// about an in-progress operation.
func NewOperationLogger(logger Logger, format string, v ...interface{}) *OperationLogger {
	ol := &OperationLogger{
		sighup:  make(chan interface{}),
		logger:  logger,
		once:    &sync.Once{},
		message: fmt.Sprintf(format, v...),
		wg:      &sync.WaitGroup{},
	}
	ol.wg.Add(1)
	go ol.logloop()
	return ol
}

// OperationLogger logs about an in-progress operation
type OperationLogger struct {
	logger  Logger
	message string
	once    *sync.Once
	sighup  chan interface{}
	wg      *sync.WaitGroup
}

func (ol *OperationLogger) logloop() {
	defer ol.wg.Done()
	timer := time.NewTimer(500 * time.Millisecond)
	defer timer.Stop()
	select {
	case <-timer.C:
		ol.logger.Infof("%s... in progress", ol.message)
	case <-ol.sighup:
		// we'll emit directly in stop
	}
}

func (ol *OperationLogger) Stop(err error) {
	ol.once.Do(func() {
		close(ol.sighup)
		ol.wg.Wait()
		if err != nil {
			ol.logger.Infof("%s... %s", ol.message, err.Error())
			return
		}
		ol.logger.Infof("%s... ok", ol.message)
	})
}