"""Command-line interface for OligoSeeker"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_cli.ipynb.

# %% auto 0
__all__ = ['create_parser', 'validate_args', 'args_to_config', 'run_cli', 'main']

# %% ../nbs/04_cli.ipynb 4
import argparse
import sys
import logging
import os
from typing import List, Optional

from .merge import merge_count_csvs
from .pipeline import PipelineConfig, OligoCodonPipeline

# %% ../nbs/04_cli.ipynb 6
def create_parser() -> argparse.ArgumentParser:
    """Create command-line argument parser.
    
    Returns:
        Configured argument parser
    """
    parser = argparse.ArgumentParser(
        description="OligoSeeker: Process FASTQ files to count oligo codons",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    
    # Mode selection
    parser.add_argument('-m', '--mode', dest='mode', 
                        choices=['count', 'merge'],
                        default='count',
                        help="Operation mode: 'count' to process FASTQ files or 'merge' to combine CSV counts")
    
    # Count mode options
    count_group = parser.add_argument_group("Count Mode Options")
    
    count_group.add_argument('--f1', '--fastq_1', dest='fastq_path_1',
                        default="../test_fastq_files/test_1.fq.gz",
                        help="Path to FASTQ 1 file (required for count mode)")
    
    count_group.add_argument('--f2', '--fastq_2', dest='fastq_path_2',
                        default="../test_fastq_files/test_2.fq.gz",
                        help="Path to FASTQ 2 file (required for count mode)")
    
    # Oligo source (at least one required for count mode)
    oligo_group = parser.add_argument_group("Oligo Source Options")
    
    oligo_group.add_argument('--oligos-file', dest='oligos_file',
                           help="File containing oligo sequences (one per line)")
    
    oligo_group.add_argument('--oligos', dest='oligos_string',
                             default="GCGGATTACATTNNNAAATAACATCGT,TGTGGTAAGCGGNNNGAAAGCATTTGT,GTCGTAGAAAATNNNTGGGTGATGAGC",
                           help="Comma-separated list of oligo sequences")
    
    oligo_group.add_argument('--offset', dest='offset_oligo', type=int, default=1,
                        help="Value to add to oligo index in output") 

    # Merge mode options
    merge_group = parser.add_argument_group("Merge Mode Options")
    
    merge_group.add_argument('--input-dir', dest='input_dir',
                           help="Directory containing CSV files to merge (required for merge mode)")
    
    merge_group.add_argument('--output-file', dest='output_file', 
                           default="merged_counts.csv",
                           help="Name of the output merged file")
    
    merge_group.add_argument('--pattern', dest='pattern', 
                           default="*count*.csv",
                           help="Pattern to match CSV files")
    
    # Common options
    parser.add_argument('-o', '--output', dest='output_path', default="../test_files/test_outs",
                        help="Output directory for results")
    
    parser.add_argument('--prefix', dest='output_prefix', default="",
                        help="Prefix for output files")
    

    
    # Logging options
    parser.add_argument('--log-file', dest='log_file',
                        help="Path to log file (if not specified, logs to console only)")
    
    parser.add_argument('--log-level', dest='log_level', default="INFO",
                        choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
                        help="Logging level")
    
    return parser

# %% ../nbs/04_cli.ipynb 8
def validate_args(args: argparse.Namespace) -> bool:
    """Validate command-line arguments.
    
    Args:
        args: Parsed command-line arguments
        
    Returns:
        True if arguments are valid, False otherwise
    """
    # Only validate count mode arguments
    if args.mode == 'count':
        if not (args.oligos_file or args.oligos_string):
            print("Error: You must specify either --oligos-file or --oligos in count mode")
            return False
            
        if args.oligos_file and not os.path.exists(args.oligos_file):
            print(f"Error: Oligos file does not exist: {args.oligos_file}")
            return False
            
        if not os.path.exists(args.fastq_path_1):
            print(f"Error: FASTQ file 1 does not exist: {args.fastq_path_1}")
            return False
        
        if not os.path.exists(args.fastq_path_2):
            print(f"Error: FASTQ file 2 does not exist: {args.fastq_path_2}")
            return False
    
    # Merge mode validation happens in run_cli
    return True

# %% ../nbs/04_cli.ipynb 9
def args_to_config(args: argparse.Namespace) -> PipelineConfig:
    """Convert command-line arguments to pipeline configuration.
    
    Args:
        args: Parsed command-line arguments
        
    Returns:
        Pipeline configuration object
    """
    # Convert log level string to int
    log_level = getattr(logging, args.log_level)
    
    return PipelineConfig(
        fastq_1=args.fastq_path_1,
        fastq_2=args.fastq_path_2,
        oligos_file=args.oligos_file,
        oligos_string=args.oligos_string,
        oligos_list=None,  # Not used in CLI
        output_path=args.output_path,
        output_prefix=args.output_prefix,
        offset_oligo=args.offset_oligo,
        log_file=args.log_file,
        log_level=log_level
    )

# %% ../nbs/04_cli.ipynb 10
def run_cli(args: Optional[List[str]] = None) -> int:
    """Run the command-line interface.
    
    Args:
        args: Command-line arguments (if None, uses sys.argv)
        
    Returns:
        Exit code (0 for success, non-zero for failure)
    """
    parser = create_parser()
    
    # When testing, avoid sys.exit() errors by just returning the error code
    is_testing = 'ipykernel' in sys.modules or os.environ.get('NBDEV_TEST') == '1'
    
    try:
        parsed_args = parser.parse_args(args)
        
        # Handle different modes
        if parsed_args.mode == 'merge':
            # Merge mode
            if not parsed_args.input_dir:
                print("Error: --input-dir is required for merge mode")
                return 1
            
            # Perform merge operation
            merged_df = merge_count_csvs(
                input_dir=parsed_args.input_dir,
                output_file=parsed_args.output_file,
                output_dir=parsed_args.output_path,
                pattern=parsed_args.pattern
            )
            
            print(f"\nMerge completed successfully!")
            print(f"Merged {len(merged_df)} unique codons across all input files")
            print(f"Results contain {len(merged_df.columns)} oligo columns")
            
            return 0
        
        elif parsed_args.mode == 'count':
            # Count mode - validate required arguments
            if not validate_args(parsed_args):
                parser.print_help()
                return 1
            
            # Convert args to config
            config = args_to_config(parsed_args)
            
            # When testing, we might want to mock the pipeline run
            if is_testing and os.environ.get('MOCK_PIPELINE') == '1':
                print("Mock pipeline run (for testing)")
                return 0
                
            # Run pipeline
            pipeline = OligoCodonPipeline(config)
            results = pipeline.run()
            
            # Print summary information
            print("\nResults saved to:")
            print(f"  CSV: {results['csv_path']}")
            if 'excel_path' in results:
                print(f"  Excel: {results['excel_path']}")
            if 'json_path' in results:
                print(f"  Summary JSON: {results['json_path']}")
            
            print(f"\nProcessed {results['oligos_processed']} oligos in {results['elapsed_time']:.2f} seconds")
            
            return 0
        
        else:
            print(f"Error: Unknown mode: {parsed_args.mode}")
            return 1
    
    except Exception as e:
        print(f"Error: {str(e)}")
        import traceback
        traceback.print_exc()
        return 1
    except SystemExit as e:
        # Catch SystemExit and just return the code instead of exiting
        if is_testing:
            print(f"Caught SystemExit: {e.code}")
            return e.code
        else:
            raise

# %% ../nbs/04_cli.ipynb 11
def main():
    """Main entry point for command-line execution."""
    # Only actually call sys.exit() when running as a script, not in tests or notebooks
    is_notebook_or_test = 'ipykernel' in sys.modules or 'pytest' in sys.modules or 'NBDEV_TEST' in os.environ
    
    # Use test arguments when in test/notebook environment
    if is_notebook_or_test:
        # Test count mode
        test_args = [
            '-m', 'count',
            '--f1', '../test_files/test_1.fq.gz',
            '--f2', '../test_files/test_2.fq.gz',
            '--oligos', 'GCGGATTACATTNNNAAATAACATCGT,TGTGGTAAGCGGNNNGAAAGCATTTGT,GTCGTAGAAAATNNNTGGGTGATGAGC',
            '-o', '../test_files/test_outs',
            '--prefix', 'test_cm1'
        ]
        run_cli(test_args)

        test_args = [
            '-m', 'count',
            '--f1', '../test_files/test_1.fq.gz',
            '--f2', '../test_files/test_2.fq.gz',
            '--oligos-file', '../test_files/oligos.txt',
            '-o', '../test_files/test_outs',
            '--prefix', 'test_cm2'
        ]
        run_cli(test_args)
        
        
        
        # Test merge mode
        test_args = [
            '-m', 'merge',
            '--input-dir', '../test_files/test_outs',
            '-o', '../test_files/test_outs',
            '--output-file', 'merged_results.csv'
        ]
        
        return run_cli(test_args)
    else:
        return sys.exit(run_cli())

# %% ../nbs/04_cli.ipynb 12
#| eval: false
if __name__ == "__main__":
    # For safety, wrap in try/except to catch any SystemExit
    try:
        exit_code = main()
        is_notebook_or_test = 'ipykernel' in sys.modules or 'pytest' in sys.modules or 'NBDEV_TEST' in os.environ
        if is_notebook_or_test:
            print(f"\nCLI completed with exit code: {exit_code}")
    except SystemExit as e:
        # Just in case, catch any SystemExit and print instead
        is_notebook_or_test = 'ipykernel' in sys.modules or 'pytest' in sys.modules or 'NBDEV_TEST' in os.environ
        if is_notebook_or_test:
            print(f"\nSystemExit caught with code: {e.code}")
        else:
            raise
