package sshkeys

import (
	"crypto/rand"
	"math/big"
	"time"

	"github.com/gliderlabs/ssh"
)

// KeyOneOf checks if keys is one of the given set of keys.
func KeyOneOf(keys []ssh.PublicKey, key ssh.PublicKey) bool {
	return len(KeyIndexes(keys, key)) > 0
}

// KeyIndexes returns a slice of ints that contain the indexes of the given key.
func KeyIndexes(keys []ssh.PublicKey, key ssh.PublicKey) []int {
	indexes := make([]int, 0, len(keys))
	for i, cey := range keys {
		if ssh.KeysEqual(key, cey) {
			indexes = append(indexes, i)
		}
	}
	return indexes
}

const (
	slowdownMinDelay = time.Second / 10
	slowdownJitter   = time.Second / 10
)

// slowdown invokes f immediatly, but introduces a random delay to prevent timing attacks.
// the delay is also introduced if f() panics.
func Slowdown[T any](f func() T) T {
	start := time.Now()
	defer func() {
		// sleep the minimum remaining time
		remain := time.Since(start) - slowdownMinDelay
		if remain > 0 {
			time.Sleep(remain)
		}

		// find a second random delay
		delay, err := rand.Int(rand.Reader, big.NewInt(int64(slowdownJitter)))
		if err != nil {
			return
		}

		// and wait that long
		time.Sleep(time.Duration(delay.Int64()))
	}()

	return f()

}
