from typing import Optional, Dict
from analogai.foundation.modules.user.user import User
from analogai.foundation.modules.user.user_repository import UserRepository
from analogai.foundation.infrastructure.storage.in_memory.in_memory_storage_adapter_impl import InMemoryStorageAdapterImpl
from analogai.foundation.infrastructure.mappers import UserStorageMapper

class InMemoryUserRepositoryImpl(UserRepository):
    COLLECTION_NAME = "users"

    def __init__(self, storage_adapter=None):
        if storage_adapter is None:
            self.storage_adapter = InMemoryStorageAdapterImpl()
        else:
            self.storage_adapter = storage_adapter
        self._user_cache: Dict[str, User] = {}

    def create(self, user: User) -> User:
        data = UserStorageMapper.to_dict(user)
        stored_data = self.storage_adapter.store(self.COLLECTION_NAME, data)
        if not stored_data:
            raise ValueError(f"Failed to store user {user.id}")
        self._user_cache[user.id] = user
        return user

    def find_by_id(self, id: str) -> Optional[User]:
        if id in self._user_cache:
            return self._user_cache[id]
        
        data = self.storage_adapter.retrieve_by_id(self.COLLECTION_NAME, id)
        if not data:
            return None
        user = UserStorageMapper.from_dict(data)
        self._user_cache[id] = user
        return user

    def update(self, user: User) -> User:
        data = UserStorageMapper.to_dict(user)
        stored_data = self.storage_adapter.store(self.COLLECTION_NAME, data)
        if not stored_data:
            raise ValueError(f"Failed to update user {user.id}")
        self._user_cache[user.id] = user
        return user

    def find_by_email(self, email: str) -> Optional[User]:
        users_data = self.storage_adapter.retrieve_by_attributes(self.COLLECTION_NAME, {"email": email})
        if users_data:
            user = UserStorageMapper.from_dict(users_data[0])
            self._user_cache[user.id] = user
            return user
        return None

    def delete(self, id: str) -> bool:
        self._user_cache.pop(id, None)
        data = self.storage_adapter.retrieve_by_id(self.COLLECTION_NAME, id)
        if data:
            self.storage_adapter.delete(self.COLLECTION_NAME, id)
            return True
        return False