"""
OMNIWEB Admin - Modern auto-generated admin panel
Author: Juste Elysée MALANDILA

Features:
- Auto-generate CRUD for models
- Modern UI (Tailwind + React)
- Charts & Analytics
- Export to CSV/Excel
- Bulk actions
- Custom dashboards
- Role-based access
- Mobile responsive
- Dark mode
"""

from typing import List, Dict, Any, Optional, Callable
from datetime import datetime
import json


class AdminConfig:
    """Admin panel configuration."""
    
    def __init__(
        self,
        title: str = "OMNIWEB Admin",
        logo: str = None,
        theme: str = "light",  # light, dark, auto
        language: str = "en",
        items_per_page: int = 25,
        enable_export: bool = True,
        enable_charts: bool = True,
        enable_bulk_actions: bool = True,
    ):
        self.title = title
        self.logo = logo
        self.theme = theme
        self.language = language
        self.items_per_page = items_per_page
        self.enable_export = enable_export
        self.enable_charts = enable_charts
        self.enable_bulk_actions = enable_bulk_actions


class ModelAdmin:
    """Admin configuration for a model."""
    
    def __init__(
        self,
        model,
        list_display: List[str] = None,
        list_filter: List[str] = None,
        search_fields: List[str] = None,
        ordering: List[str] = None,
        readonly_fields: List[str] = None,
        actions: List[Callable] = None,
    ):
        self.model = model
        self.list_display = list_display or []
        self.list_filter = list_filter or []
        self.search_fields = search_fields or []
        self.ordering = ordering or []
        self.readonly_fields = readonly_fields or []
        self.actions = actions or []
    
    def get_list_display(self) -> List[str]:
        """Get fields to display in list view."""
        if self.list_display:
            return self.list_display
        
        # Auto-detect fields from model
        if hasattr(self.model, '__annotations__'):
            return list(self.model.__annotations__.keys())[:5]
        
        return []
    
    def get_queryset(self):
        """Get queryset for list view."""
        # Override this method for custom filtering
        return self.model.all()
    
    async def save_model(self, obj, request):
        """Save model instance."""
        await obj.save()
    
    async def delete_model(self, obj, request):
        """Delete model instance."""
        await obj.delete()


class AutoAdmin:
    """
    Auto-generated admin panel for OMNIWEB.
    
    Example:
        >>> from omniweb import OmniWeb, Model
        >>> from omniweb.admin import AutoAdmin
        >>> 
        >>> app = OmniWeb()
        >>> 
        >>> class User(Model):
        >>>     __table__ = "users"
        >>> 
        >>> class Post(Model):
        >>>     __table__ = "posts"
        >>> 
        >>> # Auto-generate admin
        >>> admin = AutoAdmin(app)
        >>> admin.register(User)
        >>> admin.register(Post)
        >>> 
        >>> # Admin available at /admin
    """
    
    def __init__(self, app, config: AdminConfig = None, mount_path: str = "/admin"):
        self.app = app
        self.config = config or AdminConfig()
        self.mount_path = mount_path
        self.models: Dict[str, ModelAdmin] = {}
        self._setup_routes()
    
    def _setup_routes(self):
        """Setup admin routes."""
        
        @self.app.get(f"{self.mount_path}")
        async def admin_home():
            """Admin home page."""
            return self._render_admin_home()
        
        @self.app.get(f"{self.mount_path}/{{model_name}}")
        async def admin_list(model_name: str):
            """List view for model."""
            return await self._render_list_view(model_name)
        
        @self.app.get(f"{self.mount_path}/{{model_name}}/{{id}}")
        async def admin_detail(model_name: str, id: int):
            """Detail view for model."""
            return await self._render_detail_view(model_name, id)
        
        @self.app.post(f"{self.mount_path}/{{model_name}}")
        async def admin_create(model_name: str, data: dict):
            """Create new instance."""
            return await self._create_instance(model_name, data)
        
        @self.app.put(f"{self.mount_path}/{{model_name}}/{{id}}")
        async def admin_update(model_name: str, id: int, data: dict):
            """Update instance."""
            return await self._update_instance(model_name, id, data)
        
        @self.app.delete(f"{self.mount_path}/{{model_name}}/{{id}}")
        async def admin_delete(model_name: str, id: int):
            """Delete instance."""
            return await self._delete_instance(model_name, id)
        
        @self.app.get(f"{self.mount_path}/{{model_name}}/export")
        async def admin_export(model_name: str, format: str = "csv"):
            """Export data."""
            return await self._export_data(model_name, format)
        
        @self.app.get(f"{self.mount_path}/stats")
        async def admin_stats():
            """Admin statistics."""
            return await self._get_stats()
    
    def register(self, model, admin_class: ModelAdmin = None):
        """
        Register model with admin.
        
        Example:
            >>> admin.register(User)
            >>> 
            >>> # Or with custom config
            >>> class UserAdmin(ModelAdmin):
            >>>     list_display = ['id', 'email', 'username']
            >>>     list_filter = ['is_active']
            >>>     search_fields = ['email', 'username']
            >>> 
            >>> admin.register(User, UserAdmin)
        """
        model_name = model.__name__.lower()
        
        if admin_class:
            self.models[model_name] = admin_class(model)
        else:
            self.models[model_name] = ModelAdmin(model)
    
    def _render_admin_home(self) -> dict:
        """Render admin home page."""
        return {
            "title": self.config.title,
            "models": [
                {
                    "name": name,
                    "verbose_name": name.capitalize(),
                    "count": 0,  # TODO: Get actual count
                }
                for name in self.models.keys()
            ],
            "theme": self.config.theme,
            "language": self.config.language,
        }
    
    async def _render_list_view(self, model_name: str) -> dict:
        """Render list view for model."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Get queryset
        queryset = model_admin.get_queryset()
        
        # TODO: Implement pagination, filtering, sorting
        items = []
        if hasattr(queryset, '__aiter__'):
            async for item in queryset:
                items.append(item.dict() if hasattr(item, 'dict') else item)
        
        return {
            "model": model_name,
            "fields": model_admin.get_list_display(),
            "items": items,
            "filters": model_admin.list_filter,
            "search_fields": model_admin.search_fields,
        }
    
    async def _render_detail_view(self, model_name: str, id: int) -> dict:
        """Render detail view for model."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Get instance
        instance = await model_admin.model.get(id=id)
        
        if not instance:
            return {"error": "Not found"}, 404
        
        return {
            "model": model_name,
            "instance": instance.dict() if hasattr(instance, 'dict') else instance,
        }
    
    async def _create_instance(self, model_name: str, data: dict) -> dict:
        """Create new instance."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Create instance
        instance = model_admin.model(**data)
        await model_admin.save_model(instance, None)
        
        return {
            "message": "Created successfully",
            "instance": instance.dict() if hasattr(instance, 'dict') else instance,
        }
    
    async def _update_instance(self, model_name: str, id: int, data: dict) -> dict:
        """Update instance."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Get instance
        instance = await model_admin.model.get(id=id)
        
        if not instance:
            return {"error": "Not found"}, 404
        
        # Update fields
        for key, value in data.items():
            setattr(instance, key, value)
        
        await model_admin.save_model(instance, None)
        
        return {
            "message": "Updated successfully",
            "instance": instance.dict() if hasattr(instance, 'dict') else instance,
        }
    
    async def _delete_instance(self, model_name: str, id: int) -> dict:
        """Delete instance."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Get instance
        instance = await model_admin.model.get(id=id)
        
        if not instance:
            return {"error": "Not found"}, 404
        
        await model_admin.delete_model(instance, None)
        
        return {"message": "Deleted successfully"}
    
    async def _export_data(self, model_name: str, format: str) -> dict:
        """Export data to CSV/Excel."""
        if model_name not in self.models:
            return {"error": "Model not found"}, 404
        
        model_admin = self.models[model_name]
        
        # Get all instances
        queryset = model_admin.get_queryset()
        
        items = []
        if hasattr(queryset, '__aiter__'):
            async for item in queryset:
                items.append(item.dict() if hasattr(item, 'dict') else item)
        
        # TODO: Convert to CSV/Excel format
        
        return {
            "format": format,
            "data": items,
            "filename": f"{model_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.{format}"
        }
    
    async def _get_stats(self) -> dict:
        """Get admin statistics."""
        stats = {}
        
        for model_name, model_admin in self.models.items():
            # TODO: Get actual count
            stats[model_name] = {
                "total": 0,
                "last_updated": datetime.now().isoformat(),
            }
        
        return stats
