"""DATAVOXEL Model. Author: Juste Elysée MALANDILA"""
from typing import Any, Dict, List, Optional, ClassVar
import asyncio


class Model:
    """Base model for database tables with full CRUD operations."""
    
    __table__: ClassVar[str] = ""
    __database__: ClassVar[str] = "default"
    _instances: ClassVar[Dict[int, 'Model']] = {}
    _next_id: ClassVar[int] = 1
    
    def __init__(self, **kwargs):
        """Initialize model instance."""
        self.id: Optional[int] = kwargs.get('id')
        
        # Set attributes from kwargs
        for key, value in kwargs.items():
            if key != 'id':
                setattr(self, key, value)
        
        # Auto-generate annotations if not present
        if not hasattr(self.__class__, '__annotations__'):
            self.__class__.__annotations__ = {}
    
    async def save(self) -> 'Model':
        """Save instance to database (memory for now)."""
        if self.id is None:
            # New instance - insert
            self.id = self.__class__._next_id
            self.__class__._next_id += 1
            self.__class__._instances[self.id] = self
        else:
            # Existing instance - update
            self.__class__._instances[self.id] = self
        
        return self
    
    def save_sync(self) -> 'Model':
        """Synchronous save."""
        return asyncio.run(self.save())
    
    async def delete(self) -> bool:
        """Delete instance from database."""
        if self.id and self.id in self.__class__._instances:
            del self.__class__._instances[self.id]
            return True
        return False
    
    def delete_sync(self) -> bool:
        """Synchronous delete."""
        return asyncio.run(self.delete())
    
    @classmethod
    async def get(cls, **filters) -> Optional['Model']:
        """Get single instance by filters."""
        instances = await cls.filter(**filters)
        return instances[0] if instances else None
    
    @classmethod
    def get_sync(cls, **filters) -> Optional['Model']:
        """Synchronous get."""
        return asyncio.run(cls.get(**filters))
    
    @classmethod
    async def filter(cls, **filters) -> List['Model']:
        """Get multiple instances by filters."""
        results = []
        
        for instance in cls._instances.values():
            match = True
            for key, value in filters.items():
                if not hasattr(instance, key) or getattr(instance, key) != value:
                    match = False
                    break
            
            if match:
                results.append(instance)
        
        return results
    
    @classmethod
    def filter_sync(cls, **filters) -> List['Model']:
        """Synchronous filter."""
        return asyncio.run(cls.filter(**filters))
    
    @classmethod
    async def all(cls) -> List['Model']:
        """Get all instances."""
        return list(cls._instances.values())
    
    @classmethod
    def all_sync(cls) -> List['Model']:
        """Synchronous all."""
        return asyncio.run(cls.all())
    
    @classmethod
    async def count(cls) -> int:
        """Count all instances."""
        return len(cls._instances)
    
    @classmethod
    def count_sync(cls) -> int:
        """Synchronous count."""
        return asyncio.run(cls.count())
    
    @classmethod
    async def bulk_create(cls, instances: List[Dict[str, Any]]) -> List['Model']:
        """Create multiple instances at once."""
        created = []
        for data in instances:
            instance = cls(**data)
            await instance.save()
            created.append(instance)
        return created
    
    @classmethod
    def bulk_create_sync(cls, instances: List[Dict[str, Any]]) -> List['Model']:
        """Synchronous bulk create."""
        return asyncio.run(cls.bulk_create(instances))
    
    def dict(self) -> Dict[str, Any]:
        """Convert instance to dictionary."""
        result = {}
        
        # Get all non-private attributes
        for key, value in self.__dict__.items():
            if not key.startswith('_'):
                result[key] = value
        
        return result
    
    def __repr__(self) -> str:
        """String representation."""
        class_name = self.__class__.__name__
        attrs = ', '.join(f"{k}={v!r}" for k, v in self.dict().items())
        return f"{class_name}({attrs})"
