package azure

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"sync"
	"time"

	azure "github.com/MSOpenTech/azure-sdk-for-go/clients/storage"
)

type blockIDGenerator struct {
	pool map[string]bool
	r    *rand.Rand
	m    sync.Mutex
}

// Generate returns an unused random block id and adds the generated ID
// to list of used IDs so that the same block name is not used again.
func (b *blockIDGenerator) Generate() string {
	b.m.Lock()
	defer b.m.Unlock()

	var id string
	for {
		id = toBlockID(int(b.r.Int()))
		if !b.exists(id) {
			break
		}
	}
	b.pool[id] = true
	return id
}

func (b *blockIDGenerator) exists(id string) bool {
	_, used := b.pool[id]
	return used
}

func (b *blockIDGenerator) Feed(blocks azure.BlockListResponse) {
	b.m.Lock()
	defer b.m.Unlock()

	for _, bl := range append(blocks.CommittedBlocks, blocks.UncommittedBlocks...) {
		b.pool[bl.Name] = true
	}
}

func newBlockIDGenerator() *blockIDGenerator {
	return &blockIDGenerator{
		pool: make(map[string]bool),
		r:    rand.New(rand.NewSource(time.Now().UnixNano()))}
}

// toBlockId converts given integer to base64-encoded block ID of a fixed length.
func toBlockID(i int) string {
	s := fmt.Sprintf("%029d", i) // add zero padding for same length-blobs
	return base64.StdEncoding.EncodeToString([]byte(s))
}