package backends

import (
	"context"
	"time"
)

// MemoryBackend wraps MemoryCacheBackend to implement the CacheBackend interface
type MemoryBackend struct {
	*MemoryCacheBackend
}

// NewMemoryBackend creates a new memory backend from a config
func NewMemoryBackend(config *Config) (*MemoryBackend, error) {
	maxSize := int64(config.MaxSize)
	if maxSize <= 0 {
		maxSize = 1000
	}

	cacheBackend := NewMemoryCacheBackend(maxSize, config.MaxMemoryBytes, config.CleanupInterval)
	return &MemoryBackend{
		MemoryCacheBackend: cacheBackend,
	}, nil
}

// Set stores a value in the cache with the specified TTL
func (m *MemoryBackend) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error {
	err := m.MemoryCacheBackend.Set(ctx, key, value, ttl)
	if err == ErrBackendUnavailable {
		return ErrBackendClosed
	}
	return err
}

// Get retrieves a value from the cache
func (m *MemoryBackend) Get(ctx context.Context, key string) ([]byte, time.Duration, bool, error) {
	val, err := m.MemoryCacheBackend.Get(ctx, key)
	if err != nil {
		if err == ErrCacheMiss {
			return nil, 0, false, nil
		}
		if err == ErrBackendUnavailable {
			return nil, 0, false, ErrBackendClosed
		}
		return nil, 0, false, err
	}

	// Get TTL using the TTL method
	ttl, ttlErr := m.MemoryCacheBackend.TTL(ctx, key)
	if ttlErr != nil {
		// If we can't get TTL, still return the value with 0 TTL
		ttl = 0
	}

	// Convert interface{} to []byte
	var valueBytes []byte
	if val != nil {
		if bytes, ok := val.([]byte); ok {
			valueBytes = bytes
		} else {
			// If it's not already []byte, return an error
			return nil, 0, false, ErrInvalidValue
		}
	}

	return valueBytes, ttl, true, nil
}

// Delete removes a key from the cache
func (m *MemoryBackend) Delete(ctx context.Context, key string) (bool, error) {
	// Check if key exists first
	exists, err := m.MemoryCacheBackend.Exists(ctx, key)
	if err != nil {
		return false, err
	}

	if !exists {
		return false, nil
	}

	err = m.MemoryCacheBackend.Delete(ctx, key)
	if err != nil {
		return false, err
	}
	return true, nil
}

// Exists checks if a key exists in the cache
func (m *MemoryBackend) Exists(ctx context.Context, key string) (bool, error) {
	return m.MemoryCacheBackend.Exists(ctx, key)
}

// Clear removes all keys from the cache
func (m *MemoryBackend) Clear(ctx context.Context) error {
	return m.MemoryCacheBackend.Clear(ctx)
}

// GetStats returns cache statistics
func (m *MemoryBackend) GetStats() map[string]interface{} {
	stats, err := m.MemoryCacheBackend.GetStats(context.Background())
	if err != nil {
		return map[string]interface{}{
			"error": err.Error(),
		}
	}

	// Convert BackendStats to map
	hitRate := float64(0)
	total := stats.Hits + stats.Misses
	if total > 0 {
		hitRate = float64(stats.Hits) / float64(total)
	}

	return map[string]interface{}{
		"type":        stats.Type,
		"hits":        stats.Hits,
		"misses":      stats.Misses,
		"sets":        stats.Sets,
		"deletes":     stats.Deletes,
		"errors":      stats.Errors,
		"evictions":   stats.Evictions,
		"size":        stats.CurrentSize,
		"max_size":    stats.MaxSize,
		"memory":      stats.MemoryUsage,
		"hit_rate":    hitRate,
		"uptime":      stats.Uptime,
		"start_time":  stats.StartTime,
		"shard_count": m.MemoryCacheBackend.GetShardCount(),
	}
}

// Close shuts down the cache backend and releases resources
func (m *MemoryBackend) Close() error {
	return m.MemoryCacheBackend.Close()
}

// Ping checks if the backend is healthy and responsive
func (m *MemoryBackend) Ping(ctx context.Context) error {
	return m.MemoryCacheBackend.Ping(ctx)
}

// Ensure MemoryBackend implements CacheBackend
var _ CacheBackend = (*MemoryBackend)(nil)
