"""
Project-level commands for the MiniMax Code CLI.

Provides commands for project initialization, scanning, and analysis.
"""

import os
import json
from typing import Any, Dict, List
from pathlib import Path

from .base import BaseCommand
from ..presentation.base import TreeNode

# Import theme system with fallback
try:
    from ..ui.theme import get_file_icon
except ImportError:
    def get_file_icon(filename):
        return "📄"


class ProjectCommands(BaseCommand):
    """Commands for project-level operations."""
    
    def init(self, args: Any) -> bool:
        """Initialize a project for MiniMax Code."""
        project_dir = os.path.abspath(args.directory)
        
        self.print_info(f"Initializing MiniMax Code project in {project_dir}")
        
        # Create .minimax directory
        minimax_dir = os.path.join(project_dir, '.minimax')
        if not os.path.exists(minimax_dir):
            os.makedirs(minimax_dir)
            self.print_success(f"Created .minimax directory")
        
        # Create project configuration
        config = {
            "version": "1.0",
            "project_name": os.path.basename(project_dir),
            "language": self._detect_project_language(project_dir),
            "ignore_patterns": [
                "*.pyc", "__pycache__", "node_modules", ".git",
                "*.log", "*.tmp", ".DS_Store"
            ],
            "important_files": [],
            "context_files": []
        }
        
        config_path = os.path.join(minimax_dir, 'config.json')
        try:
            with open(config_path, 'w') as f:
                json.dump(config, f, indent=2)
            self.print_success(f"Created project configuration: {config_path}")
        except Exception as e:
            self.print_error(f"Failed to create config: {e}")
            return False
        
        # Create .gitignore entry for .minimax if .gitignore exists
        gitignore_path = os.path.join(project_dir, '.gitignore')
        if os.path.exists(gitignore_path):
            with open(gitignore_path, 'r') as f:
                content = f.read()
            
            if '.minimax' not in content:
                with open(gitignore_path, 'a') as f:
                    f.write('\n# MiniMax Code\n.minimax/\n')
                self.print_success("Added .minimax to .gitignore")
        
        self.print_success("Project initialized successfully!")
        self.print_info("Use 'minimax-code project scan' to analyze your project structure")
        
        return True
    
    def scan(self, args: Any) -> bool:
        """Scan project structure and files."""
        project_dir = os.path.abspath(args.directory)
        max_depth = args.depth
        
        if not os.path.exists(project_dir):
            self.print_error(f"Directory not found: {project_dir}")
            return False
        
        self.print_info(f"Scanning project: {project_dir}")
        self.print_info(f"Max depth: {max_depth}")
        
        # Scan the project
        project_info = self._scan_directory(project_dir, max_depth)
        
        # Display results using rich presentation
        project_name = os.path.basename(project_dir)
        
        # Show project statistics as a table
        stats_data = [
            {"Metric": "Total Files", "Value": str(project_info['total_files'])},
            {"Metric": "Total Directories", "Value": str(project_info['total_dirs'])},
            {"Metric": "Languages Detected", "Value": ', '.join(project_info['languages']) if project_info['languages'] else 'None'},
            {"Metric": "Project Type", "Value": project_info.get('project_type', 'Unknown')}
        ]
        
        self.show_markdown(f"# 📁 Project Analysis: {project_name}\n\n## Project Statistics")
        self.show_table(stats_data, title="Project Overview")
        
        # Show file types as a table
        if project_info['file_types']:
            file_types_data = [
                {
                    "Extension": ext,
                    "Count": str(count),
                    "Percentage": f"{(count / project_info['total_files'] * 100):.1f}%"
                }
                for ext, count in sorted(project_info['file_types'].items(), key=lambda x: x[1], reverse=True)
            ]
            
            self.show_markdown("## 📊 File Type Distribution")
            self.show_table(file_types_data, title="File Types")
        
        # Show directory structure using enhanced tree display
        self.show_markdown("## 🌳 Directory Structure")
        tree_data = self._convert_structure_to_tree_nodes(project_info['structure'], project_dir, project_name)
        self.show_tree(tree_data, max_depth=max_depth)
        
        # Show important files as a table
        if project_info['important_files']:
            important_files_data = []
            for file_path in project_info['important_files']:
                rel_path = os.path.relpath(file_path, project_dir)
                file_stat = os.stat(file_path) if os.path.exists(file_path) else None
                
                important_files_data.append({
                    "File": rel_path,
                    "Type": self._get_file_purpose(os.path.basename(file_path)),
                    "Size": self._format_file_size(file_stat.st_size) if file_stat else "Unknown",
                    "Modified": self._format_timestamp(file_stat.st_mtime) if file_stat else "Unknown"
                })
            
            self.show_markdown("## 📋 Important Files")
            self.show_table(important_files_data, title="Key Project Files")
        else:
            self.show_markdown("## 📋 Important Files\n\nNo important files detected in this project.")
        
        # Save scan results if .minimax exists
        minimax_dir = os.path.join(project_dir, '.minimax')
        if os.path.exists(minimax_dir):
            scan_path = os.path.join(minimax_dir, 'last_scan.json')
            try:
                with open(scan_path, 'w') as f:
                    json.dump(project_info, f, indent=2, default=str)
                self.print_success(f"Scan results saved to {scan_path}")
            except Exception as e:
                self.print_warning(f"Could not save scan results: {e}")
        
        return True
    
    def summary(self, args: Any) -> bool:
        """Generate a project summary."""
        project_dir = os.path.abspath(args.directory)
        include_files = args.include_files
        
        if not os.path.exists(project_dir):
            self.print_error(f"Directory not found: {project_dir}")
            return False
        
        self.print_info(f"Generating summary for {project_dir}...")
        
        # Scan the project first
        project_info = self._scan_directory(project_dir, depth=2)
        
        # Read important files if requested
        file_contents = {}
        if include_files:
            for file_path in project_info['important_files'][:5]:  # Limit to 5 files
                content = self.read_file(file_path)
                if content:
                    rel_path = os.path.relpath(file_path, project_dir)
                    file_contents[rel_path] = content[:1000]  # Limit content length
        
        # Create summary prompt
        prompt = f"""
Please analyze this project and provide a comprehensive summary in markdown format:

Project: {os.path.basename(project_dir)}
Total files: {project_info['total_files']}
Languages: {', '.join(project_info['languages'])}
File types: {dict(list(project_info['file_types'].items())[:10])}

Important files found:
{chr(10).join([f"- {os.path.relpath(f, project_dir)}" for f in project_info['important_files']])}

{f"File contents:{chr(10)}" + chr(10).join([f"=== {path} ==={chr(10)}{content[:500]}..." for path, content in file_contents.items()]) if file_contents else ""}

Please provide a well-structured markdown response with the following sections:

# Project Overview
- Project type and purpose (best guess)
- Primary programming language and version

# Technology Stack
- Frameworks and libraries used
- Build tools and package managers
- Development dependencies

# Project Structure
- Key directories and their purposes
- Important configuration files
- Entry points and main modules

# Key Components
- Core modules and their roles
- External dependencies
- Configuration and setup files

# Development Workflow
- Recommended development setup
- Build and deployment process
- Testing strategy

# Recommendations
- Potential areas for improvement
- Best practices to implement
- Security considerations

Format the response with proper markdown headers, lists, and code blocks where appropriate.
"""
        
        # Get AI response
        response = self.ask_ai(prompt)
        if not response:
            self.print_error("Failed to generate project summary")
            return False
        
        # Display the summary using markdown formatting
        self.show_markdown(response)
        
        return True
    
    def _scan_directory(self, directory: str, depth: int = 3) -> Dict:
        """Scan a directory and return project information."""
        project_info = {
            'total_files': 0,
            'total_dirs': 0,
            'languages': set(),
            'file_types': {},
            'structure': {},
            'important_files': [],
            'project_type': 'Unknown'
        }
        
        # Important file patterns
        important_patterns = [
            'README.md', 'README.txt', 'README.rst',
            'package.json', 'requirements.txt', 'Cargo.toml', 'pom.xml',
            'setup.py', 'pyproject.toml', 'Dockerfile', 'docker-compose.yml',
            'main.py', 'app.py', 'index.js', 'main.js', 'index.html',
            'LICENSE', 'CHANGELOG.md', '.gitignore', 'Makefile', 'CMakeLists.txt'
        ]
        
        # Build directory structure
        project_info['structure'] = self._build_directory_structure(directory, depth)
        
        # Walk through directory for file analysis
        for root, dirs, files in os.walk(directory):
            # Skip hidden directories and common ignore patterns
            dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__pycache__', 'venv', 'env']]
            
            # Check depth
            current_depth = root.replace(directory, '').count(os.sep)
            if current_depth >= depth:
                dirs.clear()  # Don't go deeper
            
            project_info['total_dirs'] += len(dirs)
            
            for file in files:
                if file.startswith('.'):
                    continue
                
                file_path = os.path.join(root, file)
                project_info['total_files'] += 1
                
                # Track file extensions
                ext = os.path.splitext(file)[1].lower()
                if ext:
                    project_info['file_types'][ext] = project_info['file_types'].get(ext, 0) + 1
                    
                    # Detect languages
                    language = self.detect_language(file_path)
                    if language != 'text':
                        project_info['languages'].add(language)
                
                # Check for important files
                if file in important_patterns:
                    project_info['important_files'].append(file_path)
        
        project_info['languages'] = list(project_info['languages'])
        project_info['project_type'] = self._detect_project_type(project_info)
        return project_info
    
    def _detect_project_language(self, directory: str) -> str:
        """Detect the primary language of a project."""
        language_indicators = {
            'python': ['requirements.txt', 'setup.py', 'pyproject.toml', '*.py'],
            'javascript': ['package.json', 'node_modules', '*.js'],
            'typescript': ['tsconfig.json', '*.ts'],
            'java': ['pom.xml', 'build.gradle', '*.java'],
            'go': ['go.mod', '*.go'],
            'rust': ['Cargo.toml', '*.rs'],
            'csharp': ['*.csproj', '*.cs'],
            'php': ['composer.json', '*.php']
        }
        
        for language, indicators in language_indicators.items():
            for indicator in indicators:
                if indicator.startswith('*.'):
                    # Check for file extensions
                    ext = indicator[1:]
                    for root, dirs, files in os.walk(directory):
                        if any(f.endswith(ext) for f in files):
                            return language
                else:
                    # Check for specific files
                    if os.path.exists(os.path.join(directory, indicator)):
                        return language
        
        return 'unknown'
    
    def _build_directory_structure(self, directory: str, max_depth: int = 3) -> Dict:
        """Build a nested dictionary representing the directory structure."""
        structure = {}
        
        try:
            # Get all items in the directory
            items = []
            for item in os.listdir(directory):
                item_path = os.path.join(directory, item)
                
                # Skip hidden files and common ignore patterns
                if item.startswith('.') or item in ['node_modules', '__pycache__', 'venv', 'env']:
                    continue
                
                try:
                    is_dir = os.path.isdir(item_path)
                    is_link = os.path.islink(item_path)
                    items.append({
                        'name': item,
                        'path': item_path,
                        'is_dir': is_dir,
                        'is_link': is_link
                    })
                except (OSError, PermissionError):
                    # Handle permission errors gracefully
                    continue
            
            # Sort items: directories first, then files, both alphabetically
            items.sort(key=lambda x: (not x['is_dir'], x['name'].lower()))
            
            for item in items:
                if item['is_dir'] and max_depth > 1:
                    # Recursively build subdirectory structure
                    try:
                        structure[item['name']] = {
                            'type': 'directory',
                            'is_link': item['is_link'],
                            'children': self._build_directory_structure(item['path'], max_depth - 1)
                        }
                    except (OSError, PermissionError):
                        # Handle permission errors for subdirectories
                        structure[item['name']] = {
                            'type': 'directory',
                            'is_link': item['is_link'],
                            'children': {},
                            'error': 'Permission denied'
                        }
                elif item['is_dir']:
                    # Directory at max depth - don't recurse
                    structure[item['name']] = {
                        'type': 'directory',
                        'is_link': item['is_link'],
                        'children': {}
                    }
                else:
                    # File
                    structure[item['name']] = {
                        'type': 'file',
                        'is_link': item['is_link']
                    }
        
        except (OSError, PermissionError):
            # Handle permission errors for the directory itself
            pass
        
        return structure
    
    def _convert_structure_to_tree_nodes(self, structure: Dict, base_path: str, root_name: str = "Project") -> TreeNode:
        """Convert directory structure to TreeNode objects for presenter."""
        def convert_node(name: str, info: Dict, full_path: str) -> TreeNode:
            # Get file stats if the path exists
            metadata = {
                'type': info['type'],
                'is_link': info.get('is_link', False),
                'path': full_path
            }
            
            if os.path.exists(full_path):
                try:
                    stat_info = os.stat(full_path)
                    metadata.update({
                        'size': stat_info.st_size,
                        'modified': stat_info.st_mtime,
                        'permissions': oct(stat_info.st_mode)[-3:]
                    })
                except (OSError, PermissionError):
                    pass
            
            if info.get('error'):
                metadata['error'] = info['error']
            
            # Create TreeNode with icon from theme
            if info['type'] == 'directory':
                display_name = f"{name}/"
                icon = "📁"
                if info.get('is_link'):
                    display_name += " → (symlink)"
                if info.get('error'):
                    display_name += f" ⚠️ ({info['error']})"
            else:
                display_name = name
                icon = get_file_icon(name)
                if info.get('is_link'):
                    display_name += " → (symlink)"
            
            node = TreeNode(
                name=display_name,
                metadata=metadata,
                icon=icon
            )
            
            # Add children if it's a directory
            if info['type'] == 'directory' and 'children' in info and info['children']:
                for child_name, child_info in info['children'].items():
                    child_path = os.path.join(full_path, child_name)
                    child_node = convert_node(child_name, child_info, child_path)
                    node.add_child(child_node)
            
            return node
        
        # Create root node
        root_node = TreeNode(
            name=f"{root_name}/",
            metadata={'type': 'directory', 'path': base_path},
            icon="📁"
        )
        
        # Add all top-level items
        for name, info in structure.items():
            child_path = os.path.join(base_path, name)
            child_node = convert_node(name, info, child_path)
            root_node.add_child(child_node)
        
        return root_node
    
    def _detect_project_type(self, project_info: Dict) -> str:
        """Detect the type of project based on files and structure."""
        important_files = [os.path.basename(f) for f in project_info['important_files']]
        languages = project_info['languages']
        
        # Web application detection
        if 'package.json' in important_files:
            if 'typescript' in languages:
                return 'TypeScript Web Application'
            else:
                return 'JavaScript Web Application'
        
        # Python project detection
        if any(f in important_files for f in ['requirements.txt', 'pyproject.toml', 'setup.py']):
            if 'main.py' in important_files or 'app.py' in important_files:
                return 'Python Application'
            else:
                return 'Python Library/Package'
        
        # Other language detection
        if 'Cargo.toml' in important_files:
            return 'Rust Project'
        if 'pom.xml' in important_files:
            return 'Java Maven Project'
        if 'go.mod' in important_files:
            return 'Go Module'
        if 'Dockerfile' in important_files:
            return 'Containerized Application'
        
        # Fallback based on primary language
        if languages:
            primary_lang = languages[0].title()
            return f'{primary_lang} Project'
        
        return 'Unknown Project Type'
    
    def _get_file_purpose(self, filename: str) -> str:
        """Get the purpose/description of an important file."""
        name_lower = filename.lower()
        
        purpose_map = {
            'readme.md': 'Documentation',
            'readme.txt': 'Documentation', 
            'readme.rst': 'Documentation',
            'license': 'License',
            'license.txt': 'License',
            'license.md': 'License',
            'package.json': 'Node.js Dependencies',
            'requirements.txt': 'Python Dependencies',
            'pyproject.toml': 'Python Project Config',
            'setup.py': 'Python Setup Script',
            'cargo.toml': 'Rust Dependencies',
            'pom.xml': 'Maven Dependencies',
            'dockerfile': 'Container Config',
            'docker-compose.yml': 'Container Orchestration',
            'main.py': 'Main Entry Point',
            'app.py': 'Application Entry Point',
            'index.js': 'JavaScript Entry Point',
            'index.html': 'Web Entry Point',
            '.gitignore': 'Git Ignore Rules',
            'changelog.md': 'Change History',
            'makefile': 'Build Configuration',
            'cmakelists.txt': 'CMake Build Config'
        }
        
        return purpose_map.get(name_lower, 'Configuration')
    
    def _format_file_size(self, size_bytes: int) -> str:
        """Format file size in human-readable format."""
        if size_bytes == 0:
            return "0 B"
        
        size_names = ["B", "KB", "MB", "GB"]
        i = 0
        size = float(size_bytes)
        
        while size >= 1024.0 and i < len(size_names) - 1:
            size /= 1024.0
            i += 1
        
        return f"{size:.1f} {size_names[i]}"
    
    def _format_timestamp(self, timestamp: float) -> str:
        """Format timestamp in human-readable format."""
        import datetime
        dt = datetime.datetime.fromtimestamp(timestamp)
        return dt.strftime("%Y-%m-%d %H:%M")
