"""
File system CLI commands for Metis Agent.

Provides command-line interface for file operations including:
- File listing and exploration
- Reading and writing files  
- File search capabilities
- Directory tree visualization
"""

import click
from pathlib import Path
from ..tools.filesystem import FileSystemTool
from ..tools.project_context import ProjectContextTool


def format_file_size(size_bytes: int) -> str:
    """Format file size in human-readable format."""
    if size_bytes == 0:
        return "0B"
    
    size_names = ["B", "KB", "MB", "GB", "TB"]
    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_file_list(result: dict) -> None:
    """Format and display file listing results."""
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    click.echo(f"Directory: {result['directory']}")
    click.echo()
    
    # Display directories first
    if result["directories"]:
        click.echo(click.style("Directories:", fg="blue", bold=True))
        for dir_info in result["directories"]:
            contents = f"({dir_info['contents_count']} items)" if isinstance(dir_info['contents_count'], int) else ""
            click.echo(f"  📁 {dir_info['name']} {contents}")
        click.echo()
    
    # Display files
    if result["files"]:
        click.echo(click.style("Files:", fg="green", bold=True))
        for file_info in result["files"]:
            size_str = format_file_size(file_info['size'])
            click.echo(f"  📄 {file_info['name']} ({size_str})")
    
    click.echo()
    click.echo(f"Total: {result['total_directories']} directories, {result['total_files']} files")


def format_tree_display(tree: dict, prefix: str = "", is_last: bool = True) -> None:
    """Recursively display directory tree."""
    connector = "└── " if is_last else "├── "
    icon = "📁" if tree["type"] == "directory" else "📄"
    
    name = tree["name"]
    if tree["type"] == "file" and "size" in tree:
        name += f" ({format_file_size(tree['size'])})"
    elif tree["type"] == "directory" and tree.get("truncated"):
        name += " ..."
    
    click.echo(f"{prefix}{connector}{icon} {name}")
    
    if tree["type"] == "directory" and "children" in tree:
        extension = "    " if is_last else "│   "
        new_prefix = prefix + extension
        
        children = tree["children"]
        for i, child in enumerate(children):
            format_tree_display(child, new_prefix, i == len(children) - 1)


@click.group()
def files():
    """File system operations."""
    pass


@files.command("list")
@click.argument("directory", default=".")
@click.option("-a", "--all", is_flag=True, help="Show hidden files")
@click.option("-r", "--recursive", is_flag=True, help="List files recursively")
@click.option("-p", "--pattern", default="*", help="File pattern to match")
def list_files(directory, all, recursive, pattern):
    """List files and directories."""
    fs_tool = FileSystemTool()
    result = fs_tool.list_files(
        directory=directory,
        pattern=pattern,
        show_hidden=all,
        recursive=recursive
    )
    format_file_list(result)


@files.command("read")
@click.argument("filepath")
@click.option("-e", "--encoding", default="utf-8", help="File encoding")
@click.option("-n", "--lines", type=int, help="Number of lines to show")
def read_file(filepath, encoding, lines):
    """Read and display file contents."""
    fs_tool = FileSystemTool()
    result = fs_tool.read_file(filepath, encoding=encoding)
    
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    # Display file info
    click.echo(click.style(f"File: {result['filepath']}", fg="blue", bold=True))
    click.echo(f"Size: {format_file_size(result['size'])}")
    click.echo(f"Lines: {result.get('lines', 'N/A')}")
    click.echo(f"Modified: {result['modified']}")
    click.echo(f"Encoding: {result['encoding']}")
    click.echo()
    
    if result.get("is_binary"):
        click.echo(click.style("Binary file - content not displayed", fg="yellow"))
        return
    
    content = result["content"]
    
    # Limit lines if specified
    if lines:
        content_lines = content.splitlines()
        if len(content_lines) > lines:
            content = "\n".join(content_lines[:lines])
            click.echo(click.style(f"Showing first {lines} lines (of {len(content_lines)} total):", fg="yellow"))
            click.echo()
    
    # Display content with line numbers for readability
    for i, line in enumerate(content.splitlines(), 1):
        click.echo(f"{i:4d}: {line}")


@files.command("write")
@click.argument("filepath")
@click.option("-c", "--content", help="Content to write to file")
@click.option("-i", "--input", "input_file", help="Read content from another file")
@click.option("-e", "--encoding", default="utf-8", help="File encoding")
@click.option("--no-backup", is_flag=True, help="Don't create backup of existing file")
def write_file(filepath, content, input_file, encoding, no_backup):
    """Write content to a file."""
    if not content and not input_file:
        # Read from stdin if no content provided
        click.echo("Enter content (press Ctrl+D when finished):")
        try:
            content = click.get_text_stream('stdin').read()
        except KeyboardInterrupt:
            click.echo("\nOperation cancelled")
            return
    
    if input_file:
        try:
            with open(input_file, 'r', encoding=encoding) as f:
                content = f.read()
        except Exception as e:
            click.echo(click.style(f"Error reading input file: {e}", fg="red"))
            return
    
    fs_tool = FileSystemTool()
    result = fs_tool.write_file(
        filepath=filepath,
        content=content,
        encoding=encoding,
        backup=not no_backup
    )
    
    if result.get("success"):
        click.echo(click.style(f"✓ File written: {result['filepath']}", fg="green"))
        click.echo(f"Size: {format_file_size(result['size'])}")
        click.echo(f"Lines: {result['lines']}")
        if result.get("backup_created"):
            click.echo(f"Backup created: {result['backup_created']}")
    else:
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))


@files.command("search")
@click.argument("pattern")
@click.option("-d", "--directory", default=".", help="Directory to search in")
@click.option("-c", "--content", is_flag=True, help="Search file contents instead of names")
@click.option("-i", "--case-insensitive", is_flag=True, help="Case insensitive search")
@click.option("-t", "--type", "file_types", multiple=True, help="File types to search (e.g., py, js)")
def search_files(pattern, directory, content, case_insensitive, file_types):
    """Search for files by name or content."""
    fs_tool = FileSystemTool()
    result = fs_tool.search_files(
        pattern=pattern,
        directory=directory,
        content_search=content,
        case_sensitive=not case_insensitive,
        file_types=list(file_types) if file_types else None
    )
    
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    search_type = "content" if content else "filename"
    click.echo(f"Searching for '{pattern}' in {search_type} within '{result['directory']}'")
    click.echo()
    
    if not result["results"]:
        click.echo(click.style("No matches found", fg="yellow"))
        return
    
    click.echo(click.style(f"Found {result['total_matches']} matches:", fg="green", bold=True))
    click.echo()
    
    for match in result["results"]:
        if content:
            # Content search results
            click.echo(click.style(f"📄 {match['file']}", fg="blue", bold=True))
            click.echo(f"   {match['match_count']} matches:")
            
            for match_info in match["matches"][:5]:  # Show first 5 matches per file
                click.echo(f"   Line {match_info['line']}: {match_info['content']}")
            
            if match['match_count'] > 5:
                click.echo(f"   ... and {match['match_count'] - 5} more matches")
            click.echo()
        else:
            # Filename search results
            icon = "📁" if match["type"] == "directory" else "📄"
            size_info = f" ({format_file_size(match['size'])})" if match.get("size") else ""
            click.echo(f"  {icon} {match['file']}{size_info}")


@files.command("tree")
@click.option("-d", "--directory", default=".", help="Directory to show tree for")
@click.option("--depth", default=3, help="Maximum depth to display")
@click.option("-a", "--all", is_flag=True, help="Show hidden files")
def show_tree(directory, depth, all):
    """Display directory tree structure."""
    fs_tool = FileSystemTool()
    result = fs_tool.get_tree(
        directory=directory,
        max_depth=depth,
        show_hidden=all
    )
    
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    click.echo(f"Directory tree for: {result['directory']}")
    click.echo(f"Max depth: {result['max_depth']}")
    click.echo()
    
    format_tree_display(result["tree"])


@click.group()
def project():
    """Project analysis and context operations."""
    pass


@project.command("analyze")
@click.option("-d", "--directory", default=".", help="Directory to analyze")
def analyze_project(directory):
    """Analyze project structure and context."""
    project_tool = ProjectContextTool()
    result = project_tool.analyze_directory(directory)
    
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    # Display project information
    click.echo(click.style(f"Project Analysis: {result['project_name']}", fg="blue", bold=True))
    click.echo(f"Directory: {result['directory']}")
    click.echo()
    
    # Project types
    if result["project_types"]:
        click.echo(click.style("Detected Project Types:", fg="green", bold=True))
        for pt in result["project_types"]:
            confidence_color = "green" if pt["confidence"] >= 70 else "yellow" if pt["confidence"] >= 40 else "red"
            click.echo(f"  • {pt['type']} ({click.style(f"{pt['confidence']}%", fg=confidence_color)})")
        click.echo()
    
    # Configuration files
    if result["config_files"]:
        click.echo(click.style("Configuration Files:", fg="cyan", bold=True))
        for cf in result["config_files"]:
            if "error" in cf:
                click.echo(f"  ❌ {cf['name']} - {cf['error']}")
            else:
                size_str = format_file_size(cf['size'])
                click.echo(f"  📄 {cf['name']} ({size_str}) - {cf['type']}")
                
                if "content" in cf and cf["name"] == "package.json":
                    content = cf["content"]
                    click.echo(f"     Name: {content.get('name', 'N/A')}")
                    click.echo(f"     Version: {content.get('version', 'N/A')}")
                    if content.get("scripts"):
                        click.echo(f"     Scripts: {', '.join(content['scripts'])}")
        click.echo()
    
    # Dependencies
    if result["dependencies"]:
        click.echo(click.style("Dependencies:", fg="magenta", bold=True))
        for lang, deps in result["dependencies"].items():
            click.echo(f"  {lang.title()}:")
            if lang == "javascript":
                if deps.get("production"):
                    click.echo(f"    Production: {len(deps['production'])} packages")
                if deps.get("development"):
                    click.echo(f"    Development: {len(deps['development'])} packages")
            elif lang == "python" and "requirements" in deps:
                click.echo(f"    Requirements: {len(deps['requirements'])} packages")
        click.echo()
    
    # Structure overview
    structure = result["structure"]
    click.echo(click.style("Project Structure:", fg="yellow", bold=True))
    click.echo(f"  Total files: {structure['total_files']}")
    click.echo(f"  Total directories: {structure['total_directories']}")
    
    # File types
    if structure["file_types"]:
        click.echo("  File types:")
        for ext, count in sorted(structure["file_types"].items(), key=lambda x: x[1], reverse=True):
            click.echo(f"    {ext}: {count}")
    click.echo()
    
    # Recommendations
    if result["recommendations"]:
        click.echo(click.style("Recommendations:", fg="blue", bold=True))
        for recommendation in result["recommendations"]:
            click.echo(f"  💡 {recommendation}")


@project.command("summary")
@click.option("-d", "--directory", default=".", help="Directory to summarize")
def project_summary(directory):
    """Get a concise project summary."""
    project_tool = ProjectContextTool()
    result = project_tool.get_project_summary(directory)
    
    if not result.get("success"):
        click.echo(click.style(f"Error: {result.get('error', 'Unknown error')}", fg="red"))
        return
    
    summary = result["summary"]
    
    click.echo(click.style(f"📊 {summary['project_name']}", fg="blue", bold=True))
    click.echo(f"Language: {summary['primary_language'] or 'Unknown'}")
    if summary['framework']:
        click.echo(f"Framework: {summary['framework']}")
    click.echo(f"Files: {summary['file_count']}")
    
    if summary['key_features']:
        click.echo(f"Features: {', '.join(summary['key_features'])}")
