import requests
import json
from pathlib import Path
from typing import List, Dict, Optional
from rich.console import Console
from rich.table import Table

console = Console()


class PluginMarketplace:
    """Plugin marketplace client"""
    
    def __init__(self, registry_url: str = "https://plugins.featheros.dev/api"):
        self.registry_url = registry_url
        self.cache_dir = Path.home() / '.feather' / 'cache'
        self.cache_dir.mkdir(parents=True, exist_ok=True)
    
    def search(self, query: str = '', category: Optional[str] = None, limit: int = 20) -> List[Dict]:
        """Search for plugins in the marketplace"""
        params = {
            'query': query,
            'limit': limit
        }
        
        if category:
            params['category'] = category
        
        try:
            response = requests.get(f"{self.registry_url}/plugins/search", params=params, timeout=10)
            response.raise_for_status()
            return response.json()['plugins']
        except requests.RequestException as e:
            console.print(f"[red]Error searching marketplace: {e}[/red]")
            return []
    
    def get_plugin_info(self, plugin_name: str) -> Optional[Dict]:
        """Get detailed info about a plugin"""
        try:
            response = requests.get(f"{self.registry_url}/plugins/{plugin_name}", timeout=10)
            response.raise_for_status()
            return response.json()
        except requests.RequestException as e:
            console.print(f"[red]Error fetching plugin info: {e}[/red]")
            return None
    
    def list_featured(self) -> List[Dict]:
        """List featured plugins"""
        try:
            response = requests.get(f"{self.registry_url}/plugins/featured", timeout=10)
            response.raise_for_status()
            return response.json()['plugins']
        except requests.RequestException as e:
            console.print(f"[red]Error fetching featured plugins: {e}[/red]")
            return []
    
    def list_categories(self) -> List[str]:
        """List all plugin categories"""
        try:
            response = requests.get(f"{self.registry_url}/categories", timeout=10)
            response.raise_for_status()
            return response.json()['categories']
        except requests.RequestException as e:
            console.print(f"[red]Error fetching categories: {e}[/red]")
            return []
    
    def get_download_url(self, plugin_name: str, version: Optional[str] = None) -> Optional[str]:
        """Get download URL for a plugin"""
        params = {}
        if version:
            params['version'] = version
        
        try:
            response = requests.get(
                f"{self.registry_url}/plugins/{plugin_name}/download",
                params=params,
                timeout=10
            )
            response.raise_for_status()
            return response.json()['download_url']
        except requests.RequestException as e:
            console.print(f"[red]Error getting download URL: {e}[/red]")
            return None
    
    def publish_plugin(self, plugin_path: Path, api_key: str) -> bool:
        """Publish a plugin to the marketplace"""
        manifest_file = plugin_path / 'plugin.json'
        
        if not manifest_file.exists():
            console.print("[red]plugin.json not found[/red]")
            return False
        
        with open(manifest_file, 'r') as f:
            manifest = json.load(f)
        
        import zipfile
        import tempfile
        
        with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as tmp:
            with zipfile.ZipFile(tmp.name, 'w') as zf:
                for file in plugin_path.rglob('*'):
                    if file.is_file():
                        zf.write(file, file.relative_to(plugin_path))
            
            with open(tmp.name, 'rb') as f:
                files = {'plugin': f}
                headers = {'Authorization': f'Bearer {api_key}'}
                
                try:
                    response = requests.post(
                        f"{self.registry_url}/plugins/publish",
                        files=files,
                        data=manifest,
                        headers=headers,
                        timeout=30
                    )
                    response.raise_for_status()
                    
                    console.print("[green]✓ Plugin published successfully![/green]")
                    return True
                except requests.RequestException as e:
                    console.print(f"[red]Error publishing plugin: {e}[/red]")
                    return False
    
    def install_with_validation(self, plugin_name: str, version: Optional[str] = None) -> bool:
        """Install a plugin with automated validation"""
        console.print(f"[cyan]Installing {plugin_name}...[/cyan]")
        
        plugin_info = self.get_plugin_info(plugin_name)
        if not plugin_info:
            console.print(f"[red]Plugin {plugin_name} not found[/red]")
            return False
        
        download_url = self.get_download_url(plugin_name, version)
        if not download_url:
            console.print("[red]Could not get download URL[/red]")
            return False
        
        console.print(f"[cyan]Downloading {plugin_name}...[/cyan]")
        try:
            response = requests.get(download_url, timeout=30)
            response.raise_for_status()
        except requests.RequestException as e:
            console.print(f"[red]Download failed: {e}[/red]")
            return False
        
        import tempfile
        with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as tmp:
            tmp.write(response.content)
            tmp.flush()
            
            console.print("[cyan]Validating plugin...[/cyan]")
            from .sandbox import plugin_validator
            is_valid, errors = plugin_validator.validate_plugin(Path(tmp.name))
            
            if not is_valid:
                console.print("[red]Plugin validation failed:[/red]")
                for error in errors:
                    console.print(f"  - {error}")
                return False
            
            console.print("[cyan]Checking dependencies...[/cyan]")
            if not self._check_dependencies(plugin_info):
                console.print("[red]Dependency check failed[/red]")
                return False
            
            console.print("[cyan]Running automated tests...[/cyan]")
            if not self._run_plugin_tests(Path(tmp.name)):
                console.print("[yellow]Warning: Plugin tests failed, but continuing installation[/yellow]")
            
            console.print("[cyan]Installing plugin...[/cyan]")
            import zipfile
            install_dir = Path.home() / '.feather' / 'plugins' / plugin_name
            install_dir.mkdir(parents=True, exist_ok=True)
            
            with zipfile.ZipFile(tmp.name, 'r') as zf:
                zf.extractall(install_dir)
            
            console.print(f"[green]✓ {plugin_name} installed successfully![/green]")
            return True
    
    def _check_dependencies(self, plugin_info: Dict) -> bool:
        """Check plugin dependencies"""
        dependencies = plugin_info.get('dependencies', {})
        if not dependencies:
            return True
        
        from .versioning import DependencyResolver
        resolver = DependencyResolver()
        
        satisfied, unmet = resolver.check_dependencies(dependencies)
        
        if not satisfied:
            console.print("[red]Unmet dependencies:[/red]")
            for dep in unmet:
                console.print(f"  - {dep}")
        
        return satisfied
    
    def _run_plugin_tests(self, plugin_archive: Path) -> bool:
        """Run automated tests on plugin"""
        import zipfile
        import tempfile
        
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)
            
            with zipfile.ZipFile(plugin_archive, 'r') as zf:
                zf.extractall(temp_path)
            
            test_file = temp_path / 'tests' / 'test_plugin.py'
            if not test_file.exists():
                return True
            
            import subprocess
            result = subprocess.run(
                [sys.executable, '-m', 'pytest', str(test_file), '-v'],
                cwd=str(temp_path),
                capture_output=True,
                timeout=60
            )
            
            return result.returncode == 0
    
    def display_search_results(self, plugins: List[Dict]):
        """Display search results in a table"""
        table = Table(title="Plugin Search Results")
        
        table.add_column("Name", style="cyan")
        table.add_column("Version", style="green")
        table.add_column("Description")
        table.add_column("Downloads", justify="right")
        
        for plugin in plugins:
            table.add_row(
                plugin['name'],
                plugin['version'],
                plugin['description'][:50] + '...' if len(plugin['description']) > 50 else plugin['description'],
                str(plugin.get('downloads', 0))
            )
        
        console.print(table)


marketplace = PluginMarketplace()
