package cache

import (
	"context"
	"encoding/json"
	"fmt"
	"time"
)

// Cache defines the interface for caching operations
type Cache interface {
	// Get retrieves a value from the cache
	Get(ctx context.Context, key string, value interface{}) error

	// Set stores a value in the cache with an optional expiration
	Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error

	// Delete removes a value from the cache
	Delete(ctx context.Context, key string) error

	// Clear removes all values from the cache
	Clear(ctx context.Context) error

	// GetMulti retrieves multiple values from the cache
	GetMulti(ctx context.Context, keys []string) (map[string][]byte, error)

	// SetMulti stores multiple values in the cache with an optional expiration
	SetMulti(ctx context.Context, items map[string]interface{}, expiration time.Duration) error
}

// Item represents a cache item with metadata
type Item struct {
	Key        string
	Value      interface{}
	Expiration time.Duration
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (i *Item) MarshalBinary() ([]byte, error) {
	return json.Marshal(i.Value)
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (i *Item) UnmarshalBinary(data []byte) error {
	return json.Unmarshal(data, &i.Value)
}

// KeyGenerator generates cache keys for different types of data
type KeyGenerator interface {
	// EntityKey generates a key for an entity by ID
	EntityKey(entityType string, id uint) string

	// ListKey generates a key for a list of entities
	ListKey(entityType string, page, pageSize int) string

	// QueryKey generates a key for a custom query
	QueryKey(entityType string, queryName string, params ...interface{}) string
}

// DefaultKeyGenerator implements the KeyGenerator interface
type DefaultKeyGenerator struct {
	Prefix string
}

// NewDefaultKeyGenerator creates a new DefaultKeyGenerator
func NewDefaultKeyGenerator(prefix string) *DefaultKeyGenerator {
	if prefix == "" {
		prefix = "tercul:"
	}
	return &DefaultKeyGenerator{
		Prefix: prefix,
	}
}

// EntityKey generates a key for an entity by ID
func (g *DefaultKeyGenerator) EntityKey(entityType string, id uint) string {
	return g.Prefix + entityType + ":id:" + fmt.Sprintf("%d", id)
}

// ListKey generates a key for a list of entities
func (g *DefaultKeyGenerator) ListKey(entityType string, page, pageSize int) string {
	return g.Prefix + entityType + ":list:" + fmt.Sprintf("%d:%d", page, pageSize)
}

// QueryKey generates a key for a custom query
func (g *DefaultKeyGenerator) QueryKey(entityType string, queryName string, params ...interface{}) string {
	key := g.Prefix + entityType + ":" + queryName
	for _, param := range params {
		key += ":" + fmt.Sprintf("%v", param)
	}
	return key
}
