package dbmanager

import (
	"fmt"
	"reflect"
)

// MemoryDbManager implements DbManager using in-memory storage
type MemoryDbManager[T Entity] struct {
	// In-memory database storage
	collections map[string]map[string]T
}

// NewMemoryDbManager creates a new memory-based database manager
func NewMemoryDbManager[T Entity]() *MemoryDbManager[T] {
	return &MemoryDbManager[T]{
		collections: make(map[string]map[string]T),
	}
}

// Connect initializes the memory database
func (db *MemoryDbManager[T]) Connect() error {
	// Nothing to do for memory implementation
	return nil
}

// Disconnect cleans up memory database
func (db *MemoryDbManager[T]) Disconnect() error {
	// Clear collections to free memory
	db.collections = make(map[string]map[string]T)
	return nil
}

// getCollection returns the collection for the given entity type
func (db *MemoryDbManager[T]) getCollection(entityType string) map[string]T {
	if _, exists := db.collections[entityType]; !exists {
		db.collections[entityType] = make(map[string]T)
	}
	return db.collections[entityType]
}

// Create creates a new entity in memory
func (db *MemoryDbManager[T]) Create(entityType string, entity T) error {
	collection := db.getCollection(entityType)
	id := entity.GetID()

	if _, exists := collection[id]; exists {
		return fmt.Errorf("entity with ID %s already exists in %s", id, entityType)
	}

	collection[id] = entity
	return nil
}

// GetByID retrieves an entity by ID from memory
func (db *MemoryDbManager[T]) GetByID(entityType string, id string) (T, error) {
	collection := db.getCollection(entityType)

	if entity, exists := collection[id]; exists {
		return entity, nil
	}

	var zero T
	return zero, fmt.Errorf("entity with ID %s not found in %s", id, entityType)
}

// Update updates an existing entity in memory
func (db *MemoryDbManager[T]) Update(entityType string, entity T) error {
	collection := db.getCollection(entityType)
	id := entity.GetID()

	if _, exists := collection[id]; !exists {
		return fmt.Errorf("entity with ID %s does not exist in %s", id, entityType)
	}

	collection[id] = entity
	return nil
}

// Delete deletes an entity from memory
func (db *MemoryDbManager[T]) Delete(entityType string, id string) error {
	collection := db.getCollection(entityType)

	if _, exists := collection[id]; !exists {
		return fmt.Errorf("entity with ID %s does not exist in %s", id, entityType)
	}

	delete(collection, id)
	return nil
}

// List retrieves entities based on a filter from memory
func (db *MemoryDbManager[T]) List(entityType string, filter map[string]interface{}) ([]T, error) {
	collection := db.getCollection(entityType)
	result := make([]T, 0)

	// If no filter is provided, return all entities
	if len(filter) == 0 {
		for _, entity := range collection {
			result = append(result, entity)
		}
		return result, nil
	}

	// Filter entities based on field values
	// Note: This is a simple implementation that relies on reflection
	// and might not be efficient for large datasets
	for _, entity := range collection {
		matches := true
		entityValue := reflect.ValueOf(entity)

		// For structs, we need to get the underlying value
		if entityValue.Kind() == reflect.Ptr {
			entityValue = entityValue.Elem()
		}

		for field, value := range filter {
			// Find the field in the struct
			structField := entityValue.FieldByName(field)
			if !structField.IsValid() {
				matches = false
				break
			}

			// Compare values
			fieldValue := structField.Interface()
			if fieldValue != value {
				matches = false
				break
			}
		}

		if matches {
			result = append(result, entity)
		}
	}

	return result, nil
}
