"""
chunkhive CLI - Complete version with all original pipeline commands
"""
import typer
from typing import Optional, List
from pathlib import Path
import sys
import json
from datetime import datetime

app = typer.Typer(
    name="chunkhive",
    help="Hierarchical, semantic code chunking for AI systems",
    no_args_is_help=True,
)

# ---------------------------------------------------------------------
# SIMPLE BANNER
# ---------------------------------------------------------------------
def _print_banner():
    """Simple ASCII banner"""
    print("="*60)
    print("       chunkhive - Hierarchical Code Chunking")
    print("="*60)

# ---------------------------------------------------------------------
# BASIC COMMANDS
# ---------------------------------------------------------------------

@app.command()
def version():
    """Show chunkhive version."""
    try:
        from . import __version__
        print(f"chunkhive v{__version__}")
    except:
        print("chunkhive v0.1.0")

@app.command()
def info():
    """Show system information."""
    _print_banner()
    print(f"Python: {sys.version.split()[0]}")
    print("Available: Python, Markdown, JSON, YAML, TXT, MDX files")
    print("GitHub: https://github.com/AgentAhmed/CodeAtlas")

# ---------------------------------------------------------------------
# CHUNK COMMANDS - MATCHING YOUR ORIGINAL PIPELINES
# ---------------------------------------------------------------------
chunk_app = typer.Typer()
app.add_typer(chunk_app, name="chunk")

# 1. LOCAL FILE/DIRECTORY CHUNKING (like local_pipeline.py)
@chunk_app.command("local")
def chunk_local(
    path: str = typer.Argument(..., help="Local directory or file path"),
    name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
    include: Optional[str] = typer.Option(None, "--include", help="Specific folder/file to include"),
    output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
    stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
):
    """
    Chunk local files/directories (like local_pipeline.py).
    
    Examples:
        chunkhive chunk local ./codebases --name output
        chunkhive chunk local ./codebases --name crewai_name --include crewai
        chunkhive chunk local ./path --output custom.jsonl
    """
    _print_banner()
    
    try:
        from .chunkers.repo_parser import RepoChunker
        from .export.local_exporter import export_chunks_jsonl
        
        path_obj = Path(path)
        
        if not path_obj.exists():
            print(f"ERROR: Path not found: {path}")
            return
        
        # Handle include parameter
        if include:
            path_obj = path_obj / include
            if not path_obj.exists():
                print(f"ERROR: Include path not found: {include}")
                return
        
        chunker = RepoChunker()
        all_chunks = []
        file_count = 0
        
        print(f"Processing: {path_obj}")
        
        if path_obj.is_file():
            chunks = chunker.chunk_file(path_obj)
            if chunks:
                all_chunks.extend(chunks)
                file_count = 1
        else:
            for file_path in path_obj.rglob("*"):
                if file_path.is_file():
                    try:
                        chunks = chunker.chunk_file(file_path)
                        if chunks:
                            all_chunks.extend(chunks)
                            file_count += 1
                    except Exception as e:
                        print(f"  Skipping {file_path.name}: {str(e)[:50]}")
        
        # Determine output filename
        if not output:
            if name:
                output = f"{name}.jsonl"
            elif path_obj.is_file():
                output = f"chunks_{path_obj.stem}.jsonl"
            else:
                output = f"chunks_{path_obj.name}.jsonl"
        
        if all_chunks:
            export_chunks_jsonl(all_chunks, Path(output), print_stats=stats)
            print(f"SUCCESS: Processed {file_count} files, generated {len(all_chunks)} chunks")
            print(f"Output: {output}")
        else:
            print("WARNING: No chunks generated")
        
    except Exception as e:
        print(f"ERROR: {e}")

# 2. SINGLE FILE CHUNKING (alias)
@chunk_app.command("file")
def chunk_file_cmd(
    file_path: str = typer.Argument(..., help="File to chunk"),
    output: Optional[str] = typer.Option(None, "-o", "--output"),
    stats: bool = typer.Option(False, "-s", "--stats"),
):
    """Chunk a single file."""
    chunk_local(path=file_path, output=output, stats=stats)

# 3. GIT REPOSITORY CHUNKING (like repo_pipeline.py)
@chunk_app.command("repo")
def chunk_repo_cmd(
    repo_url: str = typer.Argument(..., help="Git repository URL"),
    name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
    extensions: Optional[str] = typer.Option(
        None, "--extensions", 
        help="File extensions to include (comma-separated, e.g., .py,.md)"
    ),
    max_files: Optional[int] = typer.Option(
        None, "--max-files", 
        help="Maximum number of files to process"
    ),
    output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
    stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
):
    """
    Chunk a Git repository (like repo_pipeline.py).
    
    Examples:
        chunkhive chunk repo https://github.com/langchain-ai/langchain
        chunkhive chunk repo https://github.com/langchain-ai/langchain --name langchain_code
        chunkhive chunk repo https://github.com/langchain-ai/langchain --name langchain_code --extensions .py
        chunkhive chunk repo https://github.com/langchain-ai/langchain --name langchain_code --extensions .py --max-files 100
    """
    _print_banner()
    
    try:
        from .ingestion.repo_crawler import GitCrawler
        from .metadata.repo_metadata import RepoMetadataExtractor
        from .chunkers.repo_parser import RepoChunker
        from .export.repo_exporter import export_repo_chunks_jsonl
        
        print(f"Processing repository: {repo_url}")
        
        # Initialize crawler
        crawler = GitCrawler()
        
        # Clone repository
        repo_path = crawler.clone_repository(repo_url)
        if not repo_path:
            print(f"ERROR: Failed to clone repository: {repo_url}")
            return
        
        # Extract repository metadata
        extractor = RepoMetadataExtractor(repo_path)
        repo_metadata = extractor.extract_comprehensive_metadata()
        
        # Parse extensions
        ext_set = None
        if extensions:
            ext_set = set(ext.strip() for ext in extensions.split(","))
        
        # List files
        file_infos, file_stats = crawler.list_files_with_info(
            repo_path,
            extensions=ext_set,
            exclude_dirs={'.git', '__pycache__', 'node_modules', 'build', 'dist', '.venv'},
            skip_binary=True
        )
        
        # Apply max files limit
        if max_files and max_files > 0:
            file_infos = file_infos[:max_files]
            print(f"Limiting to {max_files} files")
        
        # Process files
        all_chunks = []
        chunker = RepoChunker()
        processed_files = 0
        
        print(f"Processing {len(file_infos)} files...")
        for file_info in file_infos:
            try:
                chunks = chunker.chunk_file(file_info.path, repo_metadata)
                if chunks:
                    all_chunks.extend(chunks)
                    processed_files += 1
                    
                    if processed_files % 10 == 0:
                        print(f"  Processed {processed_files}/{len(file_infos)} files")
                        
            except Exception as e:
                print(f"  Skipping {file_info.path.name}: {str(e)[:50]}")
        
        # Determine output filename
        if not output:
            if name:
                output = f"{name}.jsonl"
            else:
                repo_name = repo_path.name
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                output = f"chunks_{repo_name}_{timestamp}.jsonl"
        
        # Export with repository metadata
        if all_chunks:
            export_repo_chunks_jsonl(all_chunks, Path(output), repo_metadata, print_stats=stats)
            print(f"SUCCESS: Processed {processed_files} files, generated {len(all_chunks)} chunks")
            print(f"Output: {output}")
            
            # Show repository info
            basic = repo_metadata.get("basic", {})
            print(f"Repository: {basic.get('repo_name', 'N/A')}")
            print(f"Total files: {basic.get('file_count', 0)}")
            print(f"Size: {basic.get('size_mb', 0)} MB")
        else:
            print("WARNING: No chunks generated")
        
    except Exception as e:
        print(f"ERROR: {e}")
        import traceback
        traceback.print_exc()

# 4. SINGLE REPOSITORY (alias for backward compatibility)
@chunk_app.command("single")
def chunk_single_cmd(
    repo_url: str = typer.Argument(..., help="Git repository URL"),
    name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
    extensions: Optional[str] = typer.Option(
        None, "--extensions", 
        help="File extensions to include (comma-separated)"
    ),
    max_files: Optional[int] = typer.Option(
        None, "--max-files", 
        help="Maximum number of files to process"
    ),
    output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
    stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
):
    """
    Chunk a single Git repository (alias for 'repo' command).
    
    Examples:
        chunkhive chunk single https://github.com/langchain-ai/langchain
        chunkhive chunk single https://github.com/langchain-ai/langchain --name langchain_code
        chunkhive chunk single https://github.com/langchain-ai/langchain --name langchain_code --extensions .py --max-files 100
    """
    # Just call the repo function
    return chunk_repo_cmd(
        repo_url=repo_url,
        name=name,
        extensions=extensions,
        max_files=max_files,
        output=output,
        stats=stats
    )

# ---------------------------------------------------------------------
# ANALYZE COMMAND
# ---------------------------------------------------------------------

@app.command("analyze")
def analyze_cmd(
    repo_path: str = typer.Argument(..., help="Repository path or URL"),
    output: Optional[str] = typer.Option(None, "-o", "--output"),
    full: bool = typer.Option(False, "--full", help="Show full details"),
):
    """Analyze repository metadata."""
    _print_banner()
    
    try:
        from .metadata.repo_metadata import RepoMetadataExtractor
        from pathlib import Path
        
        # Check if it's a URL or local path
        if repo_path.startswith(("http://", "https://", "git@")):
            from .ingestion.repo_crawler import GitCrawler
            crawler = GitCrawler()
            repo_obj = crawler.clone_repository(repo_path)
            if not repo_obj:
                print(f"ERROR: Failed to clone repository: {repo_path}")
                return
        else:
            repo_obj = Path(repo_path)
            if not repo_obj.exists():
                print(f"ERROR: Path not found: {repo_path}")
                return
        
        print(f"Analyzing: {repo_obj}")
        extractor = RepoMetadataExtractor(repo_obj)
        analysis = extractor.extract_comprehensive_metadata()
        
        if output:
            with open(output, 'w', encoding='utf-8') as f:
                json.dump(analysis, f, indent=2, default=str)
            print(f"SUCCESS: Analysis saved to {output}")
        else:
            print("Analysis Results:")
            basic = analysis.get("basic", {})
            print(f"  Name: {basic.get('repo_name', 'N/A')}")
            print(f"  Files: {basic.get('file_count', 0)}")
            print(f"  Size: {basic.get('size_mb', 0)} MB")
            
            if full:
                print("\nFull Details:")
                print(json.dumps(analysis, indent=2, default=str))
        
    except Exception as e:
        print(f"ERROR: {e}")

# ---------------------------------------------------------------------
# MAIN
# ---------------------------------------------------------------------

if __name__ == "__main__":
    app()

# """
# CodeAtlas CLI - Complete version with all original pipeline commands
# """
# import typer
# from typing import Optional, List
# from pathlib import Path
# import sys
# import json
# from datetime import datetime

# app = typer.Typer(
#     name="codeatlas",
#     help="Semantic, hierarchical code chunking for AI systems",
#     no_args_is_help=True,
# )

# # ---------------------------------------------------------------------
# # SIMPLE BANNER
# # ---------------------------------------------------------------------
# def _print_banner():
#     """Simple ASCII banner"""
#     print("="*60)
#     print("       CodeAtlas - Semantic Code Chunking")
#     print("="*60)

# # ---------------------------------------------------------------------
# # BASIC COMMANDS
# # ---------------------------------------------------------------------

# @app.command()
# def version():
#     """Show CodeAtlas version."""
#     try:
#         from . import __version__
#         print(f"CodeAtlas v{__version__}")
#     except:
#         print("CodeAtlas v0.1.0")

# @app.command()
# def info():
#     """Show system information."""
#     _print_banner()
#     print(f"Python: {sys.version.split()[0]}")
#     print("Available: Python, Markdown, JSON, YAML, TXT, MDX files")

# # ---------------------------------------------------------------------
# # CHUNK COMMANDS - MATCHING YOUR ORIGINAL PIPELINES
# # ---------------------------------------------------------------------
# chunk_app = typer.Typer()
# app.add_typer(chunk_app, name="chunk")

# # 1. LOCAL FILE/DIRECTORY CHUNKING (like local_pipeline.py)
# @chunk_app.command("local")
# def chunk_local(
#     path: str = typer.Argument(..., help="Local directory or file path"),
#     name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
#     include: Optional[str] = typer.Option(None, "--include", help="Specific folder/file to include"),
#     output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
#     stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
# ):
#     """
#     Chunk local files/directories (like local_pipeline.py).
    
#     Examples:
#         codeatlas chunk local ./codebases --name output
#         codeatlas chunk local ./codebases --name crewai_name --include crewai
#         codeatlas chunk local ./path --output custom.jsonl
#     """
#     _print_banner()
    
#     try:
#         from .chunkers.repo_parser import RepoChunker
#         from .export.local_exporter import export_chunks_jsonl
        
#         path_obj = Path(path)
        
#         if not path_obj.exists():
#             print(f"ERROR: Path not found: {path}")
#             return
        
#         # Handle include parameter
#         if include:
#             path_obj = path_obj / include
#             if not path_obj.exists():
#                 print(f"ERROR: Include path not found: {include}")
#                 return
        
#         chunker = RepoChunker()
#         all_chunks = []
#         file_count = 0
        
#         print(f"Processing: {path_obj}")
        
#         if path_obj.is_file():
#             chunks = chunker.chunk_file(path_obj)
#             if chunks:
#                 all_chunks.extend(chunks)
#                 file_count = 1
#         else:
#             for file_path in path_obj.rglob("*"):
#                 if file_path.is_file():
#                     try:
#                         chunks = chunker.chunk_file(file_path)
#                         if chunks:
#                             all_chunks.extend(chunks)
#                             file_count += 1
#                     except Exception as e:
#                         print(f"  Skipping {file_path.name}: {str(e)[:50]}")
        
#         # Determine output filename
#         if not output:
#             if name:
#                 output = f"{name}.jsonl"
#             elif path_obj.is_file():
#                 output = f"chunks_{path_obj.stem}.jsonl"
#             else:
#                 output = f"chunks_{path_obj.name}.jsonl"
        
#         if all_chunks:
#             export_chunks_jsonl(all_chunks, Path(output), print_stats=stats)
#             print(f"SUCCESS: Processed {file_count} files, generated {len(all_chunks)} chunks")
#             print(f"Output: {output}")
#         else:
#             print("WARNING: No chunks generated")
        
#     except Exception as e:
#         print(f"ERROR: {e}")

# # 2. SINGLE FILE CHUNKING (alias)
# @chunk_app.command("file")
# def chunk_file_cmd(
#     file_path: str = typer.Argument(..., help="File to chunk"),
#     output: Optional[str] = typer.Option(None, "-o", "--output"),
#     stats: bool = typer.Option(False, "-s", "--stats"),
# ):
#     """Chunk a single file."""
#     chunk_local(path=file_path, output=output, stats=stats)

# # 3. GIT REPOSITORY CHUNKING (like repo_pipeline.py)
# @chunk_app.command("repo")
# def chunk_repo_cmd(
#     repo_url: str = typer.Argument(..., help="Git repository URL"),
#     name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
#     extensions: Optional[str] = typer.Option(
#         None, "--extensions", 
#         help="File extensions to include (comma-separated, e.g., .py,.md)"
#     ),
#     max_files: Optional[int] = typer.Option(
#         None, "--max-files", 
#         help="Maximum number of files to process"
#     ),
#     output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
#     stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
# ):
#     """
#     Chunk a Git repository (like repo_pipeline.py).
    
#     Examples:
#         codeatlas chunk repo https://github.com/langchain-ai/langchain
#         codeatlas chunk repo https://github.com/langchain-ai/langchain --name langchain_code
#         codeatlas chunk repo https://github.com/langchain-ai/langchain --name langchain_code --extensions .py
#         codeatlas chunk repo https://github.com/langchain-ai/langchain --name langchain_code --extensions .py --max-files 100
#     """
#     _print_banner()
    
#     try:
#         from .ingestion.repo_crawler import GitCrawler
#         from .metadata.repo_metadata import RepoMetadataExtractor
#         from .chunkers.repo_parser import RepoChunker
#         from .export.repo_exporter import export_repo_chunks_jsonl
        
#         print(f"Processing repository: {repo_url}")
        
#         # Initialize crawler
#         crawler = GitCrawler()
        
#         # Clone repository
#         repo_path = crawler.clone_repository(repo_url)
#         if not repo_path:
#             print(f"ERROR: Failed to clone repository: {repo_url}")
#             return
        
#         # Extract repository metadata
#         extractor = RepoMetadataExtractor(repo_path)
#         repo_metadata = extractor.extract_comprehensive_metadata()
        
#         # Parse extensions
#         ext_set = None
#         if extensions:
#             ext_set = set(ext.strip() for ext in extensions.split(","))
        
#         # List files
#         file_infos, file_stats = crawler.list_files_with_info(
#             repo_path,
#             extensions=ext_set,
#             exclude_dirs={'.git', '__pycache__', 'node_modules', 'build', 'dist', '.venv'},
#             skip_binary=True
#         )
        
#         # Apply max files limit
#         if max_files and max_files > 0:
#             file_infos = file_infos[:max_files]
#             print(f"Limiting to {max_files} files")
        
#         # Process files
#         all_chunks = []
#         chunker = RepoChunker()
#         processed_files = 0
        
#         print(f"Processing {len(file_infos)} files...")
#         for file_info in file_infos:
#             try:
#                 chunks = chunker.chunk_file(file_info.path, repo_metadata)
#                 if chunks:
#                     all_chunks.extend(chunks)
#                     processed_files += 1
                    
#                     if processed_files % 10 == 0:
#                         print(f"  Processed {processed_files}/{len(file_infos)} files")
                        
#             except Exception as e:
#                 print(f"  Skipping {file_info.path.name}: {str(e)[:50]}")
        
#         # Determine output filename
#         if not output:
#             if name:
#                 output = f"{name}.jsonl"
#             else:
#                 repo_name = repo_path.name
#                 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
#                 output = f"chunks_{repo_name}_{timestamp}.jsonl"
        
#         # Export with repository metadata
#         if all_chunks:
#             export_repo_chunks_jsonl(all_chunks, Path(output), repo_metadata, print_stats=stats)
#             print(f"SUCCESS: Processed {processed_files} files, generated {len(all_chunks)} chunks")
#             print(f"Output: {output}")
            
#             # Show repository info
#             basic = repo_metadata.get("basic", {})
#             print(f"Repository: {basic.get('repo_name', 'N/A')}")
#             print(f"Total files: {basic.get('file_count', 0)}")
#             print(f"Size: {basic.get('size_mb', 0)} MB")
#         else:
#             print("WARNING: No chunks generated")
        
#     except Exception as e:
#         print(f"ERROR: {e}")
#         import traceback
#         traceback.print_exc()

# # 4. SINGLE REPOSITORY (alias for backward compatibility)
# @chunk_app.command("single")
# def chunk_single_cmd(
#     repo_url: str = typer.Argument(..., help="Git repository URL"),
#     name: Optional[str] = typer.Option(None, "--name", help="Output name prefix"),
#     extensions: Optional[str] = typer.Option(
#         None, "--extensions", 
#         help="File extensions to include (comma-separated)"
#     ),
#     max_files: Optional[int] = typer.Option(
#         None, "--max-files", 
#         help="Maximum number of files to process"
#     ),
#     output: Optional[str] = typer.Option(None, "-o", "--output", help="Output file path"),
#     stats: bool = typer.Option(False, "-s", "--stats", help="Show statistics"),
# ):
#     """
#     Chunk a single Git repository (alias for 'repo' command).
    
#     Examples:
#         codeatlas chunk single https://github.com/langchain-ai/langchain
#         codeatlas chunk single https://github.com/langchain-ai/langchain --name langchain_code
#         codeatlas chunk single https://github.com/langchain-ai/langchain --name langchain_code --extensions .py --max-files 100
#     """
#     # Just call the repo function
#     return chunk_repo_cmd(
#         repo_url=repo_url,
#         name=name,
#         extensions=extensions,
#         max_files=max_files,
#         output=output,
#         stats=stats
#     )

# # ---------------------------------------------------------------------
# # ANALYZE COMMAND
# # ---------------------------------------------------------------------

# @app.command("analyze")
# def analyze_cmd(
#     repo_path: str = typer.Argument(..., help="Repository path or URL"),
#     output: Optional[str] = typer.Option(None, "-o", "--output"),
#     full: bool = typer.Option(False, "--full", help="Show full details"),
# ):
#     """Analyze repository metadata."""
#     _print_banner()
    
#     try:
#         from .metadata.repo_metadata import RepoMetadataExtractor
#         from pathlib import Path
        
#         # Check if it's a URL or local path
#         if repo_path.startswith(("http://", "https://", "git@")):
#             from .ingestion.repo_crawler import GitCrawler
#             crawler = GitCrawler()
#             repo_obj = crawler.clone_repository(repo_path)
#             if not repo_obj:
#                 print(f"ERROR: Failed to clone repository: {repo_path}")
#                 return
#         else:
#             repo_obj = Path(repo_path)
#             if not repo_obj.exists():
#                 print(f"ERROR: Path not found: {repo_path}")
#                 return
        
#         print(f"Analyzing: {repo_obj}")
#         extractor = RepoMetadataExtractor(repo_obj)
#         analysis = extractor.extract_comprehensive_metadata()
        
#         if output:
#             with open(output, 'w', encoding='utf-8') as f:
#                 json.dump(analysis, f, indent=2, default=str)
#             print(f"SUCCESS: Analysis saved to {output}")
#         else:
#             print("Analysis Results:")
#             basic = analysis.get("basic", {})
#             print(f"  Name: {basic.get('repo_name', 'N/A')}")
#             print(f"  Files: {basic.get('file_count', 0)}")
#             print(f"  Size: {basic.get('size_mb', 0)} MB")
            
#             if full:
#                 print("\nFull Details:")
#                 print(json.dumps(analysis, indent=2, default=str))
        
#     except Exception as e:
#         print(f"ERROR: {e}")

# # ---------------------------------------------------------------------
# # MAIN
# # ---------------------------------------------------------------------

# if __name__ == "__main__":
#     app()