"""
Django Revolution Zone Management

Zone detection, management, and URL pattern generation.
"""

from pathlib import Path
from typing import Dict, List, Any, Optional

try:
    from django.urls import path, include
    from django.apps import apps
    DJANGO_AVAILABLE = True
except ImportError:
    DJANGO_AVAILABLE = False

from ..config import DjangoRevolutionSettings, ZoneModel
from ..utils import Logger, ErrorHandler


class ZoneManager:
    """Manages API zones and URL pattern generation."""
    
    def __init__(self, config: DjangoRevolutionSettings):
        """Initialize zone manager with configuration."""
        self.config = config
        self.logger = Logger("zone_manager")
        self.error_handler = ErrorHandler(self.logger)
        
        # Track found and missing apps during URL generation
        self.found_apps = []
        self.missing_apps = []
    
    @property
    def zones(self) -> Dict[str, ZoneModel]:
        """Get validated zone models."""
        return self.config.get_zones()
    
    def get_app_urls(self, apps_list: List[str], prefix: str = None) -> List[Any]:
        """
        Generate URL patterns for apps that have urls.py.
        
        Args:
            apps_list: List of app names
            prefix: URL prefix (defaults to config.api_prefix)
            
        Returns:
            List of URL patterns
        """
        if not DJANGO_AVAILABLE:
            self.logger.warning("Django not available, cannot generate URL patterns")
            return []
        
        if prefix is None:
            prefix = self.config.api_prefix
        
        patterns = []
        found_apps = []
        missing_apps = []
        
        for app in apps_list:
            app_name = app.split('.')[-1]
            
            try:
                # Check if app is installed
                if not apps.is_installed(app):
                    missing_apps.append(app)
                    self.logger.warning(f"App not installed: {app}")
                    continue
                
                # Try to import URLs
                module_path = f"{app}.urls"
                patterns.append(path(f"{app_name}/", include(module_path)))
                found_apps.append(app)
                self.logger.debug(f"Added URL pattern for {app}")
                
            except ImportError as e:
                missing_apps.append(app)
                self.logger.warning(f"URLs not found for {app}: {e}")
            except Exception as e:
                missing_apps.append(app)
                self.logger.error(f"Error loading URLs for {app}: {e}")
        
        # Update tracking
        self.found_apps.extend(found_apps)
        self.missing_apps.extend(missing_apps)
        
        return patterns
    
    def create_zone_urlconf_module(self, zone_name: str, zone: ZoneModel) -> str:
        """
        Create a physical URL configuration .py file for a zone and return its import path.
        """
        if not DJANGO_AVAILABLE:
            return ""

        # Create module content
        module_content = f'''
"""
Auto-generated URL configuration for zone: {zone_name}
Generated by Django Revolution
"""
from django.urls import path, include

# Zone-specific URL patterns for {zone_name}
urlpatterns = [
'''
        for app in zone.apps:
            app_name = app.split('.')[-1]
            module_content += f'    path("{self.config.api_prefix}/{app_name}/", include("{app}.urls")),\n'
        module_content += ']\n'

        # Write to a physical .py file in the zones directory
        zones_dir = Path(__file__).parent
        py_file = zones_dir / f"{zone_name}_urls.py"
        py_file.write_text(module_content, encoding="utf-8")

        module_name = f"django_revolution.zones.{zone_name}_urls"
        return module_name
    
    def create_zone_schema_patterns(self, zone_name: str, zone: ZoneModel) -> List[Any]:
        """
        Create schema URL patterns for a specific zone.
        
        Args:
            zone_name: Name of the zone
            zone: Zone model
            
        Returns:
            List of URL patterns for schema endpoints
        """
        if not DJANGO_AVAILABLE:
            return []
        
        # Create the urlconf module for this zone
        urlconf_module = self.create_zone_urlconf_module(zone_name, zone)
        
        if not urlconf_module:
            return []
        
        schema_view_name = f'{zone_name}-schema'
        swagger_view_name = f'{zone_name}-swagger'
        
        try:
            from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
            return [
                # Schema endpoint - uses specific urlconf
                path(
                    'schema/',
                    SpectacularAPIView.as_view(urlconf=urlconf_module),
                    name=schema_view_name
                ),
                # Swagger UI endpoint
                path(
                    'schema/swagger/',
                    SpectacularSwaggerView.as_view(url_name=schema_view_name),
                    name=swagger_view_name
                ),
            ]
        except ImportError:
            self.logger.warning("drf_spectacular not available, cannot create schema patterns")
            return []
        except Exception as e:
            self.logger.error(f"Failed to create schema patterns for {zone_name}: {e}")
            return []
    
    def get_zone_urls(self) -> List[Any]:
        """
        Generate URL patterns for all zones.
        
        Returns:
            List of zone URL patterns
        """
        if not DJANGO_AVAILABLE:
            return []
        
        zone_patterns = []
        
        for zone_name, zone in self.zones.items():
            try:
                zone_schema_patterns = self.create_zone_schema_patterns(zone_name, zone)
                if zone_schema_patterns:
                    zone_patterns.append(
                        path(f'schema/{zone_name}/', include(zone_schema_patterns))
                    )
                    self.logger.debug(f"Added zone patterns for: {zone_name}")
            except Exception as e:
                self.logger.error(f"Failed to create patterns for zone {zone_name}: {e}")
        
        return zone_patterns
    
    def get_zone_schema_urls(self) -> List[Any]:
        """
        Get schema URLs for all zones.
        
        Returns:
            List of schema URL patterns
        """
        return self.get_zone_urls()
    
    def get_info(self) -> Dict[str, Any]:
        """
        Get information about zones and apps.
        
        Returns:
            Dictionary with zone and app information
        """
        return {
            'zones': {name: zone.model_dump() for name, zone in self.zones.items()},
            'found_apps': self.found_apps,
            'missing_apps': self.missing_apps,
            'total_zones': len(self.zones),
            'total_found_apps': len(self.found_apps),
            'total_missing_apps': len(self.missing_apps)
        }


class ZoneDetector:
    """Detects zones from various sources including Django configuration."""
    
    def __init__(self, config: Optional[DjangoRevolutionSettings] = None, logger: Optional[Logger] = None):
        """Initialize zone detector."""
        self.config = config
        self.logger = logger or Logger("zone_detector")
        self.error_handler = ErrorHandler(self.logger)
    
    @property
    def zones(self) -> Dict[str, ZoneModel]:
        """Get zones from configuration."""
        if self.config:
            return self.config.get_zones()
        return {}
    
    def detect_zones(self) -> Dict[str, ZoneModel]:
        """
        Detect zones from all available sources.
        
        Returns:
            Dictionary of detected zones
        """
        zones = {}
        
        # Try to detect from Django configuration
        django_zones = self.detect_zones_from_django_config()
        zones.update(django_zones)
        
        # Use configuration zones
        if self.config:
            config_zones = self.config.get_zones()
            zones.update(config_zones)
        
        self.logger.info(f"Detected {len(zones)} zones")
        return zones
    
    def detect_zones_from_django_config(self) -> Dict[str, ZoneModel]:
        """
        Detect zones from Django settings or configuration.
        
        Returns:
            Dictionary of zones from Django config
        """
        zones = {}
        
        try:
            # Try to import Django settings
            from django.conf import settings
            
            # Look for API configuration
            if hasattr(settings, 'API_ZONES'):
                for zone_name, zone_config in settings.API_ZONES.items():
                    zones[zone_name] = ZoneModel(name=zone_name, **zone_config)
            
            # Look for Django Revolution settings
            if hasattr(settings, 'DJANGO_REVOLUTION'):
                revolution_config = settings.DJANGO_REVOLUTION
                if 'zones' in revolution_config:
                    for zone_name, zone_config in revolution_config['zones'].items():
                        zones[zone_name] = ZoneModel(name=zone_name, **zone_config)
            
            # Try to import API config module
            try:
                from api.urls.config import APIConfig
                api_config = APIConfig()
                if hasattr(api_config, 'zones'):
                    for zone_name, zone_config in api_config.zones.items():
                        zones[zone_name] = ZoneModel(name=zone_name, **zone_config)
            except ImportError:
                self.logger.debug("No api.urls.config.APIConfig found")
            
        except ImportError:
            self.logger.debug("Django not available for zone detection")
        except Exception as e:
            self.logger.warning(f"Error detecting zones from Django config: {e}")
        
        return zones
    
    def get_zone_names(self) -> List[str]:
        """Get list of zone names."""
        return list(self.zones.keys())
    
    def get_zone(self, name: str) -> Optional[ZoneModel]:
        """Get specific zone by name."""
        return self.zones.get(name)
    
    def validate_zone(self, zone_name: str) -> bool:
        """Validate if zone exists."""
        return zone_name in self.zones
    
    def validate_zone_apps(self, zone_name: str) -> bool:
        """
        Validate if all apps in a zone are available.
        
        Args:
            zone_name: Name of the zone to validate
            
        Returns:
            bool: True if all apps are valid
        """
        if not DJANGO_AVAILABLE:
            return False
        
        zone = self.get_zone(zone_name)
        if not zone:
            return False
        
        try:
            for app in zone.apps:
                if not apps.is_installed(app):
                    return False
            return True
        except Exception:
            return False
    
    def get_zone_apps(self, zone_name: str) -> List[str]:
        """
        Get apps for a specific zone.
        
        Args:
            zone_name: Name of the zone
            
        Returns:
            List of app names
        """
        zone = self.get_zone(zone_name)
        return zone.apps if zone else []
    
    def get_all_apps(self) -> List[str]:
        """
        Get all unique apps across all zones.
        
        Returns:
            List of all app names
        """
        all_apps = set()
        for zone in self.zones.values():
            all_apps.update(zone.apps)
        return sorted(list(all_apps))
    
    def get_zones_summary(self) -> Dict[str, Any]:
        """
        Get summary of detected zones.
        
        Returns:
            Dictionary with zone summary information
        """
        zones_info = {}
        for zone_name, zone in self.zones.items():
            zones_info[zone_name] = {
                'title': zone.title,
                'description': zone.description,
                'apps': zone.apps,
                'app_count': len(zone.apps),
                'public': zone.public,
                'auth_required': zone.auth_required,
                'version': zone.version,
                'path_prefix': zone.path_prefix
            }
        
        return {
            'total_zones': len(self.zones),
            'zone_names': list(self.zones.keys()),
            'zones': zones_info
        } 