from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
from analogai.foundation.common.design_patterns.singleton import Singleton

class QueryStorageAdapter(ABC):
    
    @abstractmethod
    def store(self, collection: str, data: Any) -> None:
        pass

    @abstractmethod
    def retrieve_by_id(self, collection: str, id: str) -> Optional[Any]:
        pass

    @abstractmethod
    def retrieve_by_attributes(self, collection: str, query: Dict[str, Any]) -> List[Any]:
        pass

    @abstractmethod
    def delete(self, collection: str, id: str) -> bool:
        pass

    @abstractmethod
    def clear(self, collection: str) -> None:
        pass

    @abstractmethod
    def query(self, collection: str, query_dict: Dict[str, Any]) -> 'QueryBuilder':
        pass

    @abstractmethod
    def count(self, collection: str, query_dict: Optional[Dict[str, Any]] = None) -> int:
        pass

class QueryBuilder:
    
    def __init__(self, storage_adapter: QueryStorageAdapter, collection: str, query_dict: Dict[str, Any]):
        self.storage_adapter = storage_adapter
        self.collection = collection
        self.query_dict = query_dict
        self._limit_start: Optional[int] = None
        self._limit_count: Optional[int] = None
    
    def limit(self, start: int, count: int) -> 'QueryBuilder':
        self._limit_start = start
        self._limit_count = count
        return self
    
    def get(self) -> List[Any]:
        results = self.storage_adapter.retrieve_by_attributes(self.collection, self.query_dict)
        
        if self._limit_start is not None and self._limit_count is not None:
            results = results[self._limit_start:self._limit_start + self._limit_count]
        
        return results
    
    def count(self) -> int:
        return self.storage_adapter.count(self.collection, self.query_dict)