"""
Module Loader
Dynamisk loading af moduler med hot-reload support
"""

import json
import logging
import importlib
import importlib.util
from pathlib import Path
from typing import Dict, List, Optional
from dataclasses import dataclass
from fastapi import FastAPI, HTTPException

logger = logging.getLogger(__name__)


@dataclass
class ModuleMetadata:
    """Metadata for et modul"""
    name: str
    version: str
    description: str
    enabled: bool
    author: str
    dependencies: List[str]
    table_prefix: str
    api_prefix: str
    tags: List[str]
    module_path: Path


class ModuleLoader:
    """
    Dynamisk modul loader med hot-reload support
    
    Moduler ligger i app/modules/{module_name}/
    Hver modul har en module.json med metadata
    """
    
    def __init__(self, modules_dir: str = "app/modules"):
        self.modules_dir = Path(modules_dir)
        self.loaded_modules: Dict[str, ModuleMetadata] = {}
        self.module_routers: Dict[str, tuple] = {}  # name -> (api_router, frontend_router)
        
    def discover_modules(self) -> List[ModuleMetadata]:
        """
        Find alle moduler i modules directory
        
        Returns:
            Liste af ModuleMetadata objekter
        """
        modules = []
        
        if not self.modules_dir.exists():
            logger.warning(f"⚠️ Modules directory ikke fundet: {self.modules_dir}")
            return modules
            
        for module_dir in self.modules_dir.iterdir():
            if not module_dir.is_dir() or module_dir.name.startswith("_"):
                continue
                
            manifest_path = module_dir / "module.json"
            if not manifest_path.exists():
                logger.warning(f"⚠️ Ingen module.json i {module_dir.name}")
                continue
                
            try:
                with open(manifest_path, 'r', encoding='utf-8') as f:
                    manifest = json.load(f)
                    
                metadata = ModuleMetadata(
                    name=manifest.get("name", module_dir.name),
                    version=manifest.get("version", "1.0.0"),
                    description=manifest.get("description", ""),
                    enabled=manifest.get("enabled", False),
                    author=manifest.get("author", "Unknown"),
                    dependencies=manifest.get("dependencies", []),
                    table_prefix=manifest.get("table_prefix", f"{module_dir.name}_"),
                    api_prefix=manifest.get("api_prefix", f"/api/v1/{module_dir.name}"),
                    tags=manifest.get("tags", [module_dir.name.title()]),
                    module_path=module_dir
                )
                
                modules.append(metadata)
                logger.info(f"📦 Fundet modul: {metadata.name} v{metadata.version} (enabled={metadata.enabled})")
                
            except Exception as e:
                logger.error(f"❌ Kunne ikke læse manifest for {module_dir.name}: {e}")
                
        return modules
        
    def load_module(self, metadata: ModuleMetadata) -> Optional[tuple]:
        """
        Load et enkelt modul (backend + frontend routers)
        
        Args:
            metadata: Modul metadata
            
        Returns:
            Tuple af (api_router, frontend_router) eller None ved fejl
        """
        if not metadata.enabled:
            logger.info(f"⏭️ Springer over disabled modul: {metadata.name}")
            return None
            
        try:
            # Check dependencies
            for dep in metadata.dependencies:
                if dep not in self.loaded_modules:
                    logger.warning(f"⚠️ Modul {metadata.name} kræver {dep} (mangler)")
                    return None
                    
            # Import backend router
            backend_path = metadata.module_path / "backend" / "router.py"
            api_router = None
            if backend_path.exists():
                spec = importlib.util.spec_from_file_location(
                    f"app.modules.{metadata.name}.backend.router",
                    backend_path
                )
                if spec and spec.loader:
                    module = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(module)
                
                if hasattr(module, 'router'):
                    api_router = module.router
                    logger.info(f"✅ Loaded API router for {metadata.name}")
                    
            # Import frontend views
            frontend_path = metadata.module_path / "frontend" / "views.py"
            frontend_router = None
            if frontend_path.exists():
                spec = importlib.util.spec_from_file_location(
                    f"app.modules.{metadata.name}.frontend.views",
                    frontend_path
                )
                if spec and spec.loader:
                    module = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(module)
                
                if hasattr(module, 'router'):
                    frontend_router = module.router
                    logger.info(f"✅ Loaded frontend router for {metadata.name}")
                    
            if api_router is None and frontend_router is None:
                logger.warning(f"⚠️ Ingen routers fundet for {metadata.name}")
                return None
                
            self.loaded_modules[metadata.name] = metadata
            self.module_routers[metadata.name] = (api_router, frontend_router)
            
            logger.info(f"🎉 Modul {metadata.name} loaded successfully")
            return (api_router, frontend_router)
            
        except Exception as e:
            logger.error(f"❌ Kunne ikke loade modul {metadata.name}: {e}", exc_info=True)
            return None
            
    def register_modules(self, app: FastAPI):
        """
        Registrer alle enabled moduler i FastAPI app
        
        Args:
            app: FastAPI application instance
        """
        modules = self.discover_modules()
        
        for metadata in modules:
            if not metadata.enabled:
                continue
                
            routers = self.load_module(metadata)
            if routers is None:
                continue
                
            api_router, frontend_router = routers
            
            # Registrer API router
            if api_router:
                try:
                    app.include_router(
                        api_router,
                        prefix=metadata.api_prefix,
                        tags=list(metadata.tags)  # type: ignore
                    )
                    logger.info(f"🔌 Registered API: {metadata.api_prefix}")
                except Exception as e:
                    logger.error(f"❌ Kunne ikke registrere API router for {metadata.name}: {e}")
                    
            # Registrer frontend router
            if frontend_router:
                try:
                    from typing import cast, List
                    frontend_tags: List[str] = ["Frontend"] + list(metadata.tags)
                    app.include_router(
                        frontend_router,
                        tags=frontend_tags  # type: ignore
                    )
                    logger.info(f"🔌 Registered Frontend for {metadata.name}")
                except Exception as e:
                    logger.error(f"❌ Kunne ikke registrere frontend router for {metadata.name}: {e}")
                    
    def get_module_status(self) -> Dict[str, dict]:
        """
        Hent status for alle loaded moduler
        
        Returns:
            Dict med modul navn -> status info
        """
        status = {}
        for name, metadata in self.loaded_modules.items():
            status[name] = {
                "name": metadata.name,
                "version": metadata.version,
                "description": metadata.description,
                "enabled": metadata.enabled,
                "author": metadata.author,
                "table_prefix": metadata.table_prefix,
                "api_prefix": metadata.api_prefix,
                "has_api": self.module_routers[name][0] is not None,
                "has_frontend": self.module_routers[name][1] is not None
            }
        return status
        
    def enable_module(self, module_name: str) -> bool:
        """
        Aktiver et modul (kræver app restart)
        
        Args:
            module_name: Navn på modul
            
        Returns:
            True hvis success
        """
        module_dir = self.modules_dir / module_name
        manifest_path = module_dir / "module.json"
        
        if not manifest_path.exists():
            raise HTTPException(status_code=404, detail=f"Modul {module_name} ikke fundet")
            
        try:
            with open(manifest_path, 'r', encoding='utf-8') as f:
                manifest = json.load(f)
                
            manifest["enabled"] = True
            
            with open(manifest_path, 'w', encoding='utf-8') as f:
                json.dump(manifest, f, indent=2, ensure_ascii=False)
                
            logger.info(f"✅ Modul {module_name} enabled (restart required)")
            return True
            
        except Exception as e:
            logger.error(f"❌ Kunne ikke enable {module_name}: {e}")
            raise HTTPException(status_code=500, detail=str(e))
            
    def disable_module(self, module_name: str) -> bool:
        """
        Deaktiver et modul (kræver app restart)
        
        Args:
            module_name: Navn på modul
            
        Returns:
            True hvis success
        """
        module_dir = self.modules_dir / module_name
        manifest_path = module_dir / "module.json"
        
        if not manifest_path.exists():
            raise HTTPException(status_code=404, detail=f"Modul {module_name} ikke fundet")
            
        try:
            with open(manifest_path, 'r', encoding='utf-8') as f:
                manifest = json.load(f)
                
            manifest["enabled"] = False
            
            with open(manifest_path, 'w', encoding='utf-8') as f:
                json.dump(manifest, f, indent=2, ensure_ascii=False)
                
            logger.info(f"⏸️ Modul {module_name} disabled (restart required)")
            return True
            
        except Exception as e:
            logger.error(f"❌ Kunne ikke disable {module_name}: {e}")
            raise HTTPException(status_code=500, detail=str(e))


# Global module loader instance
module_loader = ModuleLoader()
