package writecache

import (
	"context"
	"errors"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
	meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
)

// Info groups the information about write-cache.
type Info struct {
	// Full path to the write-cache.
	Path string
}

type SealPrm struct {
	IgnoreErrors bool
	RestoreMode  bool
	Shrink       bool
}

// Cache represents write-cache for objects.
type Cache interface {
	Get(ctx context.Context, address oid.Address) (*objectSDK.Object, error)
	Head(context.Context, oid.Address) (*objectSDK.Object, error)
	// Delete removes object referenced by the given oid.Address from the
	// Cache. Returns any error encountered that prevented the object to be
	// removed.
	//
	// Returns apistatus.ObjectNotFound if object is missing in the Cache.
	// Returns ErrReadOnly if the Cache is currently in the read-only mode.
	Delete(context.Context, oid.Address) error
	Put(context.Context, common.PutPrm) (common.PutRes, error)
	SetMode(context.Context, mode.Mode) error
	SetLogger(*logger.Logger)
	DumpInfo() Info
	Flush(context.Context, bool, bool) error
	Seal(context.Context, SealPrm) error

	Init(context.Context) error
	Open(ctx context.Context, mode mode.Mode) error
	Close(context.Context) error
	GetMetrics() Metrics
}

// MainStorage is the interface of the underlying storage of Cache implementations.
type MainStorage interface {
	Compressor() *compression.Config
	Exists(context.Context, common.ExistsPrm) (common.ExistsRes, error)
	Put(context.Context, common.PutPrm) (common.PutRes, error)
}

// Metabase is the interface of the metabase used by Cache implementations.
type Metabase interface {
	UpdateStorageID(context.Context, meta.UpdateStorageIDPrm) (meta.UpdateStorageIDRes, error)
}

var (
	// ErrReadOnly is returned when Put/Write is performed in a read-only mode.
	ErrReadOnly = logicerr.New("write-cache is in read-only mode")
	// ErrDegraded is returned when writecache is in degraded mode.
	ErrDegraded = logicerr.New("write-cache is in degraded mode")
	// ErrNotInitialized is returned when write-cache is initializing.
	ErrNotInitialized = logicerr.New("write-cache is not initialized yet")
	// ErrBigObject is returned when object is too big to be placed in cache.
	ErrBigObject = errors.New("too big object")
	// ErrOutOfSpace is returned when there is no space left to put a new object.
	ErrOutOfSpace = errors.New("no space left in the write cache")
)