package raffle

import (
	"crypto/rand"
	"encoding/binary"
	mathRand "math/rand"

	"github.com/pkg/errors"
)

type (
	cryptRandSrc struct{}
)

var errNoCandidatesLeft = errors.New("no candidates left")

func pickWinnerFromRaffle(r raffle) (winner raffleEntry, err error) {
	var maxScore float64
	for _, re := range r.Entries {
		if re.WasPicked {
			// We skip previously picked winners and pretend they
			// don't exist
			continue
		}

		maxScore += re.Multiplier
	}

	if maxScore == 0 {
		return winner, errNoCandidatesLeft
	}

	winnerPoint := mathRand.New(cryptRandSrc{}).Float64() * maxScore //#nosec:G404 - RNG is using a secure source

	for i := range r.Entries {
		re := r.Entries[i]

		if re.WasPicked {
			// We skip previously picked winners and pretend they
			// don't exist
			continue
		}

		winnerPoint -= re.Multiplier
		if winnerPoint < 0 {
			winner = re
			break
		}
	}

	return winner, nil
}

func (cryptRandSrc) Int63() int64 {
	var b [8]byte
	rand.Read(b[:])
	// mask off sign bit to ensure positive number
	return int64(binary.LittleEndian.Uint64(b[:]) & (1<<63 - 1))
}

// We're using a non-seedable source
func (cryptRandSrc) Seed(int64) {}