You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: waiter.go
    path of file: ./repos/ko/vendor/github.com/aws/smithy-go/waiter
    
    the code of the file until where you have to start completion: package waiter

import (
	"fmt"
	"math"
	"time"

	"github.com/aws/smithy-go/rand"
)

// ComputeDelay computes delay between waiter attempts. The function takes in a current attempt count,
// minimum delay, maximum delay, and remaining wait time for waiter as input. The inputs minDelay and maxDelay
// must always be greater than 0, along with minDelay lesser than or equal to maxDelay.
//
// Returns the computed delay and if next attempt count is possible with
    
func ComputeDelay(attempt int64, minDelay, maxDelay, remainingTime time.Duration) (delay time.Duration, err error) {
	// zeroth attempt, no delay
	if attempt <= 0 {
		return 0, nil
	}

	// remainingTime is zero or less, no delay
	if remainingTime <= 0 {
		return 0, nil
	}

	// validate min delay is greater than 0
	if minDelay == 0 {
		return 0, fmt.Errorf("minDelay must be greater than zero when computing Delay")
	}

	// validate max delay is greater than 0
	if maxDelay == 0 {
		return 0, fmt.Errorf("maxDelay must be greater than zero when computing Delay")
	}

	// Get attempt ceiling to prevent integer overflow.
	attemptCeiling := (math.Log(float64(maxDelay/minDelay)) / math.Log(2)) + 1

	if attempt > int64(attemptCeiling) {
		delay = maxDelay
	} else {
		// Compute exponential delay based on attempt.
		ri := 1 << uint64(attempt-1)
		// compute delay
		delay = minDelay * time.Duration(ri)
	}

	if delay != minDelay {
		// randomize to get jitter between min delay and delay value
		d, err := rand.CryptoRandInt63n(int64(delay - minDelay))
		if err != nil {
			return 0, fmt.Errorf("error computing retry jitter, %w", err)
		}

		delay = time.Duration(d) + minDelay
	}

	// check if this is the last attempt possible and compute delay accordingly
	if remainingTime-delay <= minDelay {
		delay = remainingTime - minDelay
	}

	return delay, nil
}