#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Python Package Manager CLI v3.0
Универсальный кроссплатформенный менеджер пакетов
Работает: Windows, Linux, macOS, BSD
"""

import os
import sys
import subprocess
import json
import platform
from pathlib import Path
from typing import List, Dict, Optional, Tuple
import shutil
import re

class SystemDetector:
    """Определение системы и поиск Python"""
    
    @staticmethod
    def get_os() -> str:
        """Определить ОС"""
        system = platform.system().lower()
        if system == 'windows':
            return 'windows'
        elif system == 'darwin':
            return 'macos'
        elif system == 'linux':
            return 'linux'
        elif 'bsd' in system:
            return 'bsd'
        else:
            return 'unknown'
    
    @staticmethod
    def find_python() -> Optional[Path]:
        """Найти системный Python (глобальный)"""
        os_type = SystemDetector.get_os()
        
        # Список возможных путей к Python
        python_paths = []
        
        if os_type == 'windows':
            # Windows: ищем в PATH и стандартных местах
            python_paths = [
                Path('C:/Python313/python.exe'),
                Path('C:/Python312/python.exe'),
                Path('C:/Python311/python.exe'),
                Path('C:/Python310/python.exe'),
                Path('C:/Python39/python.exe'),
                Path('C:/Python38/python.exe'),
                Path(os.environ.get('LOCALAPPDATA', '') + '/Programs/Python/Python313/python.exe'),
                Path(os.environ.get('LOCALAPPDATA', '') + '/Programs/Python/Python312/python.exe'),
                Path(os.environ.get('LOCALAPPDATA', '') + '/Programs/Python/Python311/python.exe'),
            ]
            # Проверяем PATH
            for path in os.environ.get('PATH', '').split(';'):
                if 'python' in path.lower():
                    python_paths.append(Path(path) / 'python.exe')
                    python_paths.append(Path(path) / 'python3.exe')
        else:
            # Unix-like (Linux, macOS, BSD)
            python_paths = [
                Path('/usr/bin/python3'),
                Path('/usr/local/bin/python3'),
                Path('/opt/homebrew/bin/python3'),  # macOS Homebrew
                Path('/usr/bin/python'),
                Path('/usr/local/bin/python'),
                Path('/opt/bin/python3'),
            ]
        
        # Проверяем каждый путь
        for path in python_paths:
            if path.exists() and path.is_file():
                # Проверяем, что это действительно Python
                try:
                    result = subprocess.run(
                        [str(path), '--version'],
                        capture_output=True,
                        text=True,
                        timeout=2
                    )
                    if result.returncode == 0 and 'Python' in result.stdout:
                        return path
                except:
                    continue
        
        # Если не нашли, пробуем через which/where
        try:
            if os_type == 'windows':
                result = subprocess.run(
                    ['where', 'python'],
                    capture_output=True,
                    text=True
                )
            else:
                result = subprocess.run(
                    ['which', 'python3'],
                    capture_output=True,
                    text=True
                )
            
            if result.returncode == 0 and result.stdout:
                path = Path(result.stdout.strip().split('\n')[0])
                if path.exists():
                    return path
        except:
            pass
        
        # Если ничего не нашли, используем sys.executable
        return Path(sys.executable)
    
    @staticmethod
    def is_global_python(python_path: Path) -> bool:
        """Проверить, является ли Python глобальным"""
        # Проверяем, не находится ли Python в виртуальном окружении
        python_str = str(python_path)
        
        # Признаки виртуального окружения
        venv_indicators = [
            '/venv/',
            '/.venv/',
            '/env/',
            '/.env/',
            '/virtualenv/',
            '/.virtualenv/',
            '\\venv\\',
            '\\.venv\\',
            '\\env\\',
            '\\.env\\',
            '\\virtualenv\\',
            '\\.virtualenv\\',
        ]
        
        for indicator in venv_indicators:
            if indicator in python_str:
                return False
        
        # Проверяем путь к site-packages
        try:
            result = subprocess.run(
                [str(python_path), '-c', 'import sys; print(sys.prefix)'],
                capture_output=True,
                text=True
            )
            if result.returncode == 0:
                prefix = result.stdout.strip()
                # Если prefix содержит 'venv' или 'env' - это виртуальное окружение
                if any(x in prefix.lower() for x in ['venv', 'env', 'virtualenv']):
                    return False
        except:
            pass
        
        return True

class UniversalPackageManager:
    """Универсальный менеджер пакетов для всех ОС"""
    
    def __init__(self):
        # Автоматически находим глобальный Python
        self.python_path = SystemDetector.find_python()
        self.os_type = SystemDetector.get_os()
        
        if not self.python_path or not self.python_path.exists():
            print("❌ Python не найден в системе!")
            print("   Убедитесь, что Python установлен и доступен в PATH")
            sys.exit(1)
        
        # Проверяем, что это глобальный Python
        self.is_global = SystemDetector.is_global_python(self.python_path)
        
        # Определяем пути для виртуальных окружений
        self.venv_paths = self._get_venv_paths()
        
        self._print_info()
    
    def _get_venv_paths(self) -> List[Path]:
        """Получить стандартные пути для виртуальных окружений"""
        home = Path.home()
        paths = []
        
        if self.os_type == 'windows':
            # Windows
            paths = [
                home / 'venvs',
                home / 'envs',
                home / '.virtualenvs',
                home / 'VirtualEnvs',
            ]
        else:
            # Unix-like
            paths = [
                home / '.virtualenvs',
                home / 'venvs',
                home / 'envs',
                home / 'VirtualEnvs',
                Path('/opt/venvs'),
            ]
        
        # Создаем директории, если их нет
        for path in paths:
            if not path.exists():
                try:
                    path.mkdir(parents=True, exist_ok=True)
                except:
                    pass
        
        return paths
    
    def _print_info(self):
        """Показать информацию о системе"""
        print("="*60)
        print("🐍 UNIVERSAL PACKAGE MANAGER v3.0")
        print("="*60)
        print(f"💻 ОС: {self.os_type.upper()}")
        print(f"🐍 Python: {self.python_path}")
        print(f"📦 Тип: {'Глобальный' if self.is_global else 'Виртуальное окружение'}")
        
        # Версия Python
        result = self._run_python('--version')
        if result and result.returncode == 0:
            print(f"🐍 Версия: {result.stdout.strip()}")
        
        # Версия pip
        result = self._run_pip('--version')
        if result and result.returncode == 0:
            print(f"📦 Pip: {result.stdout.strip().split()[1]}")
        
        print("="*60)
    
    def _run_python(self, *args) -> Optional[subprocess.CompletedProcess]:
        """Выполнить команду Python"""
        try:
            cmd = [str(self.python_path)] + list(args)
            return subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=30
            )
        except Exception as e:
            print(f"❌ Ошибка: {e}")
            return None
    
    def _run_pip(self, *args) -> Optional[subprocess.CompletedProcess]:
        """Выполнить команду pip через Python"""
        return self._run_python('-m', 'pip', *args)
    
    def list_packages(self) -> List[Dict]:
        """Получить список всех установленных пакетов"""
        result = self._run_pip('list', '--format=json')
        
        if result and result.returncode == 0 and result.stdout:
            try:
                return json.loads(result.stdout)
            except:
                return []
        return []
    
    def install_package(self, package: str) -> Tuple[bool, str]:
        """Установить пакет глобально"""
        result = self._run_pip('install', package)
        
        if result and result.returncode == 0:
            return True, result.stdout
        else:
            return False, result.stderr if result else "Unknown error"
    
    def uninstall_package(self, package: str) -> Tuple[bool, str]:
        """Удалить пакет глобально"""
        result = self._run_pip('uninstall', '-y', package)
        
        if result and result.returncode == 0:
            return True, result.stdout
        else:
            return False, result.stderr if result else "Unknown error"
    
    def update_package(self, package: str) -> Tuple[bool, str]:
        """Обновить пакет"""
        result = self._run_pip('install', '--upgrade', package)
        
        if result and result.returncode == 0:
            return True, result.stdout
        else:
            return False, result.stderr if result else "Unknown error"
    
    def get_outdated(self) -> List[Dict]:
        """Получить устаревшие пакеты"""
        result = self._run_pip('list', '--outdated', '--format=json')
        
        if result and result.returncode == 0 and result.stdout:
            try:
                return json.loads(result.stdout)
            except:
                return []
        return []
    
    def export_requirements(self, filename: str = None) -> bool:
        """Экспортировать зависимости"""
        if not filename:
            from datetime import datetime
            filename = f"requirements_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        
        result = self._run_pip('freeze')
        
        if result and result.returncode == 0 and result.stdout:
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(result.stdout)
                print(f"✅ Экспортировано в: {filename}")
                print(f"📊 Пакетов: {len(result.stdout.splitlines())}")
                return True
            except Exception as e:
                print(f"❌ Ошибка записи файла: {e}")
                return False
        return False
    
    def install_from_requirements(self, filename: str) -> Tuple[bool, str]:
        """Установить из requirements.txt"""
        if not os.path.exists(filename):
            return False, f"Файл не найден: {filename}"
        
        result = self._run_pip('install', '-r', filename)
        
        if result and result.returncode == 0:
            return True, result.stdout
        else:
            return False, result.stderr if result else "Unknown error"
    
    def find_venvs(self) -> List[Path]:
        """Найти все виртуальные окружения"""
        venvs = []
        
        for base_path in self.venv_paths:
            if base_path.exists():
                for item in base_path.iterdir():
                    if item.is_dir():
                        # Проверяем, что это venv
                        if self._is_venv(item):
                            venvs.append(item)
        
        # Также ищем в домашней директории
        home = Path.home()
        for item in home.iterdir():
            if item.is_dir() and not item.name.startswith('.'):
                for venv_name in ['venv', '.venv', 'env', '.env']:
                    venv_path = item / venv_name
                    if venv_path.exists() and self._is_venv(venv_path):
                        venvs.append(venv_path)
        
        return list(set(venvs))  # Удаляем дубликаты
    
    def _is_venv(self, path: Path) -> bool:
        """Проверить, является ли путь виртуальным окружением"""
        if self.os_type == 'windows':
            # Windows
            return (path / 'Scripts' / 'python.exe').exists()
        else:
            # Unix-like
            return (path / 'bin' / 'python').exists()
    
    def get_venv_python(self, venv_path: Path) -> Optional[Path]:
        """Получить путь к Python в виртуальном окружении"""
        if self.os_type == 'windows':
            python_path = venv_path / 'Scripts' / 'python.exe'
        else:
            python_path = venv_path / 'bin' / 'python'
        
        return python_path if python_path.exists() else None
    
    def get_venv_packages(self, venv_path: Path) -> List[Dict]:
        """Получить пакеты в виртуальном окружении"""
        python_path = self.get_venv_python(venv_path)
        if not python_path:
            return []
        
        try:
            # Создаем временный менеджер для venv
            temp_manager = UniversalPackageManager.__new__(UniversalPackageManager)
            temp_manager.python_path = python_path
            temp_manager.os_type = self.os_type
            
            return temp_manager.list_packages()
        except:
            return []

class PackageManagerCLI:
    """Интерактивный CLI интерфейс"""
    
    def __init__(self):
        self.pm = UniversalPackageManager()
        self.running = True
    
    def clear_screen(self):
        """Очистить экран"""
        os.system('cls' if self.pm.os_type == 'windows' else 'clear')
    
    def print_header(self):
        """Печать заголовка"""
        self.clear_screen()
        print("="*60)
        print("🐍 UNIVERSAL PACKAGE MANAGER v3.0")
        print("="*60)
        print(f"💻 {self.pm.os_type.upper()} | 🐍 {self.pm.python_path.name}")
        print("="*60)
    
    def print_menu(self):
        """Печать меню"""
        print("\n📋 ГЛАВНОЕ МЕНЮ:")
        print("  1. 📦 Показать все глобальные пакеты")
        print("  2. 🔍 Установить пакет глобально")
        print("  3. 🗑️ Удалить пакет")
        print("  4. 🔄 Обновить пакет")
        print("  5. 📊 Проверить устаревшие пакеты")
        print("  6. 📤 Экспортировать requirements.txt")
        print("  7. 📥 Установить из requirements.txt")
        print("  8. 🐍 Управление виртуальными окружениями")
        print("  9. ℹ️ Информация о системе")
        print("  0. 🚪 Выход")
        print("="*60)
    
    def get_input(self, prompt: str, default: str = "") -> str:
        """Безопасный ввод"""
        try:
            if default:
                result = input(f"{prompt} [{default}]: ").strip()
                return result if result else default
            return input(f"{prompt}: ").strip()
        except KeyboardInterrupt:
            print("\n👋 Выход...")
            self.running = False
            return ""
    
    def wait_for_enter(self):
        """Ожидание Enter"""
        input("\nНажмите Enter для продолжения...")
    
    def list_packages(self):
        """Показать пакеты"""
        self.print_header()
        print("\n📦 УСТАНОВЛЕННЫЕ ПАКЕТЫ:\n")
        
        packages = self.pm.list_packages()
        
        if not packages:
            print("❌ Пакеты не найдены")
            print("   Возможно, pip не установлен или нет пакетов")
        else:
            print(f"✅ Найдено: {len(packages)} пакетов\n")
            print(f"{'№':<4} {'Пакет':<35} {'Версия':<15}")
            print("-"*60)
            
            for i, pkg in enumerate(sorted(packages, key=lambda x: x['name'].lower()), 1):
                print(f"{i:<4} {pkg['name']:<35} {pkg['version']:<15}")
        
        self.wait_for_enter()
    
    def install_package(self):
        """Установка пакета"""
        self.print_header()
        print("\n🔍 УСТАНОВКА ПАКЕТА:\n")
        
        name = self.get_input("Введите имя пакета")
        if not name:
            return
        
        version = self.get_input("Версия (опционально, например ==1.2.3)", "")
        full_name = f"{name}{version}" if version else name
        
        print(f"\n📦 Установка {full_name}...")
        success, output = self.pm.install_package(full_name)
        
        if success:
            print(f"✅ {full_name} установлен успешно")
        else:
            print(f"❌ Ошибка установки:")
            print(output)
        
        self.wait_for_enter()
    
    def uninstall_package(self):
        """Удаление пакета"""
        self.print_header()
        print("\n🗑️ УДАЛЕНИЕ ПАКЕТА:\n")
        
        name = self.get_input("Введите имя пакета для удаления")
        if not name:
            return
        
        confirm = self.get_input(f"Удалить {name}? (y/n)", "n")
        if confirm.lower() != 'y':
            print("⚠️ Отменено")
            self.wait_for_enter()
            return
        
        print(f"\n🗑️ Удаление {name}...")
        success, output = self.pm.uninstall_package(name)
        
        if success:
            print(f"✅ {name} удален успешно")
        else:
            print(f"❌ Ошибка удаления:")
            print(output)
        
        self.wait_for_enter()
    
    def update_package(self):
        """Обновление пакета"""
        self.print_header()
        print("\n🔄 ОБНОВЛЕНИЕ ПАКЕТА:\n")
        
        outdated = self.pm.get_outdated()
        
        if not outdated:
            print("✅ Все пакеты актуальны!")
            self.wait_for_enter()
            return
        
        print("Устаревшие пакеты:")
        for i, pkg in enumerate(outdated, 1):
            print(f"  {i}. {pkg['name']}: {pkg['version']} -> {pkg['latest_version']}")
        
        print("\n0. Обновить все")
        name = self.get_input("Введите номер или имя пакета")
        
        if not name:
            return
        
        if name == '0':
            print("\n🔄 Обновление всех пакетов...")
            updated = 0
            failed = 0
            
            for pkg in outdated:
                print(f"  {pkg['name']}...", end=" ")
                success, _ = self.pm.update_package(pkg['name'])
                if success:
                    print("✅")
                    updated += 1
                else:
                    print("❌")
                    failed += 1
            
            print(f"\n✅ Обновлено: {updated}")
            if failed:
                print(f"❌ Ошибок: {failed}")
        else:
            # Пытаемся найти по номеру или имени
            try:
                idx = int(name) - 1
                if 0 <= idx < len(outdated):
                    pkg_name = outdated[idx]['name']
                else:
                    pkg_name = name
            except:
                pkg_name = name
            
            print(f"\n🔄 Обновление {pkg_name}...")
            success, output = self.pm.update_package(pkg_name)
            
            if success:
                print(f"✅ {pkg_name} обновлен")
            else:
                print(f"❌ Ошибка обновления:")
                print(output)
        
        self.wait_for_enter()
    
    def check_outdated(self):
        """Проверка устаревших"""
        self.print_header()
        print("\n📊 УСТАРЕВШИЕ ПАКЕТЫ:\n")
        
        outdated = self.pm.get_outdated()
        
        if not outdated:
            print("✅ Все пакеты актуальны!")
        else:
            print(f"Найдено устаревших: {len(outdated)}\n")
            for i, pkg in enumerate(outdated, 1):
                print(f"  {i}. {pkg['name']:<30} {pkg['version']:<12} -> {pkg['latest_version']}")
        
        self.wait_for_enter()
    
    def export_requirements(self):
        """Экспорт"""
        self.print_header()
        print("\n📤 ЭКСПОРТ REQUIREMENTS.TXT:\n")
        
        name = self.get_input("Имя файла (по умолчанию requirements_YYYYMMDD_HHMMSS.txt)", "")
        
        if name:
            success = self.pm.export_requirements(name)
        else:
            success = self.pm.export_requirements()
        
        if not success:
            print("❌ Ошибка экспорта")
        
        self.wait_for_enter()
    
    def install_requirements(self):
        """Установка из requirements.txt"""
        self.print_header()
        print("\n📥 УСТАНОВКА ИЗ REQUIREMENTS.TXT:\n")
        
        # Поиск файлов
        req_files = list(Path('.').glob('requirements*.txt'))
        
        if req_files:
            print("Найденные файлы:")
            for i, f in enumerate(req_files, 1):
                print(f"  {i}. {f.name}")
            print("  0. Указать другой файл")
            
            choice = input("Выберите файл: ").strip()
            try:
                idx = int(choice)
                if idx == 0:
                    filename = self.get_input("Путь к файлу")
                elif 1 <= idx <= len(req_files):
                    filename = str(req_files[idx - 1])
                else:
                    return
            except:
                filename = self.get_input("Путь к файлу")
        else:
            filename = self.get_input("Путь к requirements.txt")
        
        if not filename:
            return
        
        print(f"\n📥 Установка из {filename}...")
        success, output = self.pm.install_from_requirements(filename)
        
        if success:
            print("✅ Пакеты установлены успешно")
        else:
            print("❌ Ошибка установки:")
            print(output)
        
        self.wait_for_enter()
    
    def venv_management(self):
        """Управление виртуальными окружениями"""
        while True:
            self.print_header()
            print("\n🐍 УПРАВЛЕНИЕ ВИРТУАЛЬНЫМИ ОКРУЖЕНИЯМИ:\n")
            
            print("  1. 📂 Найти все виртуальные окружения")
            print("  2. ➕ Создать виртуальное окружение")
            print("  3. 🔄 Переключиться на окружение")
            print("  4. 🗑️ Удалить окружение")
            print("  5. 📦 Показать пакеты в окружении")
            print("  0. 🔙 Назад")
            print("="*60)
            
            choice = self.get_input("Выберите опцию", "0")
            
            if choice == "0":
                break
            elif choice == "1":
                self._scan_venvs()
            elif choice == "2":
                self._create_venv()
            elif choice == "3":
                self._switch_venv()
            elif choice == "4":
                self._delete_venv()
            elif choice == "5":
                self._show_venv_packages()
    
    def _scan_venvs(self):
        """Сканирование venv"""
        self.print_header()
        print("\n📂 ПОИСК ВИРТУАЛЬНЫХ ОКРУЖЕНИЙ:\n")
        
        venvs = self.pm.find_venvs()
        
        if not venvs:
            print("❌ Виртуальные окружения не найдены")
        else:
            print(f"✅ Найдено: {len(venvs)}\n")
            for i, venv in enumerate(venvs, 1):
                size = self._get_dir_size(venv)
                print(f"  {i}. {venv.name}")
                print(f"     Путь: {venv}")
                print(f"     Размер: {self._format_size(size)}\n")
        
        self.wait_for_enter()
    
    def _get_dir_size(self, path: Path) -> int:
        """Подсчет размера директории"""
        total = 0
        try:
            for item in path.rglob('*'):
                if item.is_file():
                    total += item.stat().st_size
        except:
            pass
        return total
    
    def _format_size(self, size: int) -> str:
        """Форматирование размера"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024.0:
                return f"{size:.1f} {unit}"
            size /= 1024.0
        return f"{size:.1f} TB"
    
    def _create_venv(self):
        """Создание venv"""
        self.print_header()
        print("\n➕ СОЗДАНИЕ ВИРТУАЛЬНОГО ОКРУЖЕНИЯ:\n")
        
        name = self.get_input("Имя окружения", "venv")
        if not name:
            return
        
        # Путь по умолчанию
        default_path = str(Path.cwd() / name)
        path = self.get_input("Путь для создания", default_path)
        
        venv_path = Path(path)
        
        if venv_path.exists():
            confirm = self.get_input(f"{venv_path} уже существует. Перезаписать? (y/n)", "n")
            if confirm.lower() != 'y':
                return
        
        print(f"\n🔄 Создание {venv_path}...")
        
        try:
            result = subprocess.run(
                [str(self.pm.python_path), '-m', 'venv', str(venv_path)],
                capture_output=True,
                text=True
            )
            
            if result.returncode == 0:
                print(f"✅ Виртуальное окружение создано: {venv_path}")
            else:
                print(f"❌ Ошибка создания:")
                print(result.stderr)
        except Exception as e:
            print(f"❌ Ошибка: {e}")
        
        self.wait_for_enter()
    
    def _switch_venv(self):
        """Переключение на venv"""
        self.print_header()
        print("\n🔄 ПЕРЕКЛЮЧЕНИЕ ОКРУЖЕНИЯ:\n")
        
        venvs = self.pm.find_venvs()
        
        if not venvs:
            print("❌ Виртуальные окружения не найдены")
            self.wait_for_enter()
            return
        
        print("Доступные окружения:")
        for i, venv in enumerate(venvs, 1):
            print(f"  {i}. {venv.name}")
        
        choice = self.get_input("Выберите номер (0 - глобальное)")
        
        try:
            idx = int(choice) - 1
            if choice == "0":
                self.pm = UniversalPackageManager()
                print("✅ Переключено на глобальное окружение")
            elif 0 <= idx < len(venvs):
                venv_path = venvs[idx]
                python_path = self.pm.get_venv_python(venv_path)
                if python_path:
                    # Создаем новый менеджер для venv
                    new_pm = UniversalPackageManager.__new__(UniversalPackageManager)
                    new_pm.python_path = python_path
                    new_pm.os_type = self.pm.os_type
                    self.pm = new_pm
                    print(f"✅ Переключено на: {venv_path.name}")
                else:
                    print("❌ Не удалось найти Python в окружении")
        except:
            print("❌ Неверный выбор")
        
        self.wait_for_enter()
    
    def _delete_venv(self):
        """Удаление venv"""
        self.print_header()
        print("\n🗑️ УДАЛЕНИЕ ВИРТУАЛЬНОГО ОКРУЖЕНИЯ:\n")
        
        venvs = self.pm.find_venvs()
        
        if not venvs:
            print("❌ Виртуальные окружения не найдены")
            self.wait_for_enter()
            return
        
        print("Доступные окружения:")
        for i, venv in enumerate(venvs, 1):
            print(f"  {i}. {venv.name}")
        
        choice = self.get_input("Выберите номер для удаления")
        
        try:
            idx = int(choice) - 1
            if 0 <= idx < len(venvs):
                venv_path = venvs[idx]
                confirm = self.get_input(f"Удалить {venv_path}? (y/n)", "n")
                if confirm.lower() == 'y':
                    shutil.rmtree(venv_path)
                    print(f"✅ {venv_path} удален")
        except:
            print("❌ Неверный выбор")
        
        self.wait_for_enter()
    
    def _show_venv_packages(self):
        """Показать пакеты в venv"""
        self.print_header()
        print("\n📦 ПАКЕТЫ В ВИРТУАЛЬНОМ ОКРУЖЕНИИ:\n")
        
        venvs = self.pm.find_venvs()
        
        if not venvs:
            print("❌ Виртуальные окружения не найдены")
            self.wait_for_enter()
            return
        
        print("Доступные окружения:")
        for i, venv in enumerate(venvs, 1):
            print(f"  {i}. {venv.name}")
        
        choice = self.get_input("Выберите номер")
        
        try:
            idx = int(choice) - 1
            if 0 <= idx < len(venvs):
                venv_path = venvs[idx]
                packages = self.pm.get_venv_packages(venv_path)
                
                if packages:
                    print(f"\n✅ Пакетов: {len(packages)}\n")
                    for pkg in sorted(packages, key=lambda x: x['name'].lower()):
                        print(f"  {pkg['name']:<35} {pkg['version']}")
                else:
                    print("❌ Нет пакетов или ошибка доступа")
        except:
            print("❌ Неверный выбор")
        
        self.wait_for_enter()
    
    def show_info(self):
        """Информация о системе"""
        self.print_header()
        print("\nℹ️ ИНФОРМАЦИЯ О СИСТЕМЕ:\n")
        
        packages = self.pm.list_packages()
        outdated = self.pm.get_outdated()
        
        print(f"💻 ОС: {self.pm.os_type.upper()}")
        print(f"🐍 Python: {self.pm.python_path}")
        print(f"📦 Установлено пакетов: {len(packages)}")
        print(f"🔄 Устаревших пакетов: {len(outdated)}")
        
        # Информация о pip
        result = self.pm._run_pip('--version')
        if result and result.returncode == 0:
            print(f"📦 Pip: {result.stdout.strip()}")
        
        self.wait_for_enter()
    
    def run(self):
        """Запуск"""
        while self.running:
            self.print_header()
            self.print_menu()
            
            choice = self.get_input("Выберите опцию", "0")
            
            if choice == "0":
                print("\n👋 До свидания!")
                self.running = False
            elif choice == "1":
                self.list_packages()
            elif choice == "2":
                self.install_package()
            elif choice == "3":
                self.uninstall_package()
            elif choice == "4":
                self.update_package()
            elif choice == "5":
                self.check_outdated()
            elif choice == "6":
                self.export_requirements()
            elif choice == "7":
                self.install_requirements()
            elif choice == "8":
                self.venv_management()
            elif choice == "9":
                self.show_info()
            else:
                print("❌ Неверный выбор!")

def main():
    try:
        cli = PackageManagerCLI()
        cli.run()
    except KeyboardInterrupt:
        print("\n👋 Выход...")
    except Exception as e:
        print(f"\n❌ Критическая ошибка: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)

if __name__ == "__main__":
    main()
