package vpn

import (
	"context"
	"time"

	"github.com/qdm12/gluetun/internal/constants"
	"github.com/qdm12/gluetun/internal/models"
)

func ptrTo[T any](value T) *T { return &value }

// waitForError waits 100ms for an error in the waitError channel.
func (l *Loop) waitForError(ctx context.Context,
	waitError chan error) (err error) {
	const waitDurationForError = 100 * time.Millisecond
	timer := time.NewTimer(waitDurationForError)
	select {
	case <-ctx.Done():
		if !timer.Stop() {
			<-timer.C
		}
		return ctx.Err()
	case <-timer.C:
		return nil
	case err := <-waitError:
		close(waitError)
		if !timer.Stop() {
			<-timer.C
		}
		return err
	}
}

func (l *Loop) crashed(ctx context.Context, err error) {
	l.signalOrSetStatus(constants.Crashed)
	l.logAndWait(ctx, err)
}

func (l *Loop) signalOrSetStatus(status models.LoopStatus) {
	if l.userTrigger {
		l.userTrigger = false
		select {
		case l.running <- status:
		default: // receiver calling ApplyStatus dropped out
		}
	} else {
		l.statusManager.SetStatus(status)
	}
}

func (l *Loop) logAndWait(ctx context.Context, err error) {
	if err != nil {
		l.logger.Error(err.Error())
	}
	l.logger.Info("retrying in " + l.backoffTime.String())
	timer := time.NewTimer(l.backoffTime)
	l.backoffTime *= 2
	select {
	case <-timer.C:
	case <-ctx.Done():
		if !timer.Stop() {
			<-timer.C
		}
	}
}
