package mode

import "math"

// Mode represents enumeration of Shard work modes.
type Mode uint32

const (
	// ReadWrite is a Mode value for shard that is available
	// for read and write operations. Default shard mode.
	ReadWrite Mode = 0b000

	// ReadOnly is a Mode value for shard that does not
	// accept write operation but is readable.
	ReadOnly Mode = 0b001

	// Degraded is a Mode value for shard when the metabase is unavailable.
	// It is hard to perform some modifying operations in this mode, thus it can only be set by an administrator.
	Degraded Mode = 0b010

	// Disabled mode is a mode where a shard is disabled.
	// An existing shard can't have this mode, but it can be used in
	// the configuration or control service commands.
	Disabled Mode = math.MaxUint32

	// DegradedReadOnly is a Mode value for shard that is set automatically
	// after a certain number of errors is encountered. It is the same as
	// `mode.Degraded` but also is read-only.
	DegradedReadOnly Mode = Degraded | ReadOnly
)

// ComponentMode represents basic operation modes for shared components, including READ, READ_WRITE, and DISABLED.
type ComponentMode uint32

const (
	// ComponentReadWrite is a Mode value for component that is available
	// for read and write operations. Default component mode.
	ComponentReadWrite ComponentMode = 0

	// ComponentReadOnly is a Mode value for component that does not
	// accept write operation but is readable.
	ComponentReadOnly ComponentMode = 0b001

	// ComponentDisabled mode is a mode where a component is disabled.
	ComponentDisabled ComponentMode = math.MaxUint32
)

func (m Mode) String() string {
	switch m {
	default:
		return "UNDEFINED"
	case ReadWrite:
		return "READ_WRITE"
	case ReadOnly:
		return "READ_ONLY"
	case Degraded:
		return "DEGRADED_READ_WRITE"
	case DegradedReadOnly:
		return "DEGRADED_READ_ONLY"
	case Disabled:
		return "DISABLED"
	}
}

func (m ComponentMode) String() string {
	switch m {
	default:
		return "UNDEFINED"
	case ComponentReadWrite:
		return "READ_WRITE"
	case ComponentReadOnly:
		return "READ_ONLY"
	case ComponentDisabled:
		return "CLOSED"
	}
}

// NoMetabase returns true iff m is operating without the metabase.
func (m Mode) NoMetabase() bool {
	return m&Degraded != 0
}

// ReadOnly returns true iff m prohibits modifying operations with shard.
func (m Mode) ReadOnly() bool {
	return m&ReadOnly != 0
}

// ReadOnly returns true iff m prohibits modifying operations with shard.
func (m ComponentMode) ReadOnly() bool {
	return m&ComponentReadOnly != 0
}

func (m Mode) Disabled() bool {
	return m == Disabled
}

func (m ComponentMode) Disabled() bool {
	return m == ComponentDisabled
}

// ConvertToComponentModeDegraded converts a ShardMode to a corresponding ComponentMode.
// Disables the component if the node is in degraded mode. Used in Metabase, Writecache, Pilorama.
func ConvertToComponentModeDegraded(m Mode) ComponentMode {
	if m.NoMetabase() || m.Disabled() {
		return ComponentDisabled
	}
	if m.ReadOnly() {
		return ComponentReadOnly
	}
	return ComponentReadWrite
}

// ConvertToComponentMode converts a ShardMode to a corresponding ComponentMode.
// Ignores the degraded mode of the node. Used in Blobstore.
func ConvertToComponentMode(m Mode) ComponentMode {
	if m.Disabled() {
		return ComponentDisabled
	}
	if m.ReadOnly() {
		return ComponentReadOnly
	}
	return ComponentReadWrite
}