package model

import (
	"crypto/rand"
)

var (
	CreatingClusterStatus         []ClusterStatus = []ClusterStatus{ClusterStatusInitializing, ClusterStatusPreparing, ClusterStatusLaunching}
	DeletedClusterStatus          []ClusterStatus = []ClusterStatus{ClusterStatusDeleted, ClusterStatusDeletecomplete}
	DeletedOrClearedClusterStatus []ClusterStatus = []ClusterStatus{ClusterStatusDeleted, ClusterStatusDeletecomplete, ClusterStatusCleared}
	ReadyForBackupClusterStatus   []ClusterStatus = []ClusterStatus{ClusterStatusNormal}
)

// Creating returns true if we are still creating the cluster
func (s ClusterStatus) Creating() bool {
	for _, tmp := range CreatingClusterStatus {
		if s == tmp {
			return true
		}
	}
	return false
}

// Deleted returns true if cluster is deleted
func (s ClusterStatus) Deleted() bool {
	for _, tmp := range DeletedClusterStatus {
		if s == tmp {
			return true
		}
	}
	return false
}

// DeletedOrCleared returns true if cluster is deleted or cleared
func (s ClusterStatus) DeletedOrCleared() bool {
	for _, tmp := range DeletedOrClearedClusterStatus {
		if s == tmp {
			return true
		}
	}
	return false
}

// ReadyForBackup returns true is cluster is ready for backup
func (c Cluster) ReadyForBackup() bool {
	for _, tmp := range ReadyForBackupClusterStatus {
		if c.Status == tmp {
			return true
		}
	}
	if c.Status == ClusterStatusDeleted && c.FinalBackupBeforeDelete {
		return true
	}
	return false
}

// IsDevTier returns true if cluster is dev tier
func (c Cluster) IsDevTier() bool {
	// TODO(chenfei): It is NOT the best strategy to detect whether the cluster is dev tier.
	return c.Free
}

func GenerateSalt() ([]byte, error) {
	salt := make([]byte, SaltLength)
	if _, e := rand.Read(salt); e != nil {
		return nil, e
	}
	return salt, nil
}

func MustGenerateSalt() []byte {
	salt, e := GenerateSalt()
	if e != nil {
		panic(e)
	}
	return salt
}

func IsValidSalt(salt []byte) bool {
	if len(salt) != SaltLength {
		return false
	}
	// salt shouldn't be all zero
	for _, s := range salt {
		if s != 0 {
			return true
		}
	}
	return false
}
