"""DATAVOXEL Query builder. Author: Juste Elysée MALANDILA"""
from typing import Any, List, Optional, Callable
import asyncio


class Query:
    """Type-safe query builder with method chaining."""
    
    def __init__(self, model):
        """Initialize query for a model."""
        self.model = model
        self._filters = []
        self._limit_val = None
        self._offset_val = 0
        self._order_field = None
        self._order_desc = False
    
    def where(self, **kwargs) -> 'Query':
        """Add WHERE conditions."""
        self._filters.extend(kwargs.items())
        return self
    
    def filter(self, condition: Callable) -> 'Query':
        """Add custom filter function."""
        self._filters.append(('__callable__', condition))
        return self
    
    def limit(self, n: int) -> 'Query':
        """Limit number of results."""
        self._limit_val = n
        return self
    
    def offset(self, n: int) -> 'Query':
        """Offset results."""
        self._offset_val = n
        return self
    
    def order_by(self, field: str, desc: bool = False) -> 'Query':
        """Order results by field."""
        self._order_field = field
        self._order_desc = desc
        return self
    
    async def all(self) -> List[Any]:
        """Execute query and return all results."""
        # Get all instances
        results = list(self.model._instances.values())
        
        # Apply filters
        for key, value in self._filters:
            if key == '__callable__':
                # Custom filter function
                results = [r for r in results if value(r)]
            else:
                # Simple equality filter
                results = [
                    r for r in results 
                    if hasattr(r, key) and getattr(r, key) == value
                ]
        
        # Apply ordering
        if self._order_field:
            results.sort(
                key=lambda x: getattr(x, self._order_field, None),
                reverse=self._order_desc
            )
        
        # Apply offset
        if self._offset_val:
            results = results[self._offset_val:]
        
        # Apply limit
        if self._limit_val:
            results = results[:self._limit_val]
        
        return results
    
    def all_sync(self) -> List[Any]:
        """Synchronous all."""
        return asyncio.run(self.all())
    
    async def first(self) -> Optional[Any]:
        """Get first result."""
        self._limit_val = 1
        results = await self.all()
        return results[0] if results else None
    
    def first_sync(self) -> Optional[Any]:
        """Synchronous first."""
        return asyncio.run(self.first())
    
    async def count(self) -> int:
        """Count matching results."""
        results = await self.all()
        return len(results)
    
    def count_sync(self) -> int:
        """Synchronous count."""
        return asyncio.run(self.count())
    
    async def exists(self) -> bool:
        """Check if any results exist."""
        count = await self.count()
        return count > 0
    
    def exists_sync(self) -> bool:
        """Synchronous exists."""
        return asyncio.run(self.exists())
    
    def __repr__(self) -> str:
        """String representation."""
        return f"Query({self.model.__name__}, filters={len(self._filters)})"
