"""
Enhanced Command-line interface for Themis matching README functionality.
"""

import click
import json
import sys
from pathlib import Path


@click.group()
@click.version_option()
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose output')
def cli(verbose):
    """Themis - AI Evaluation & Testing Framework.
    
    Comprehensive AI system evaluation with bias detection, 
    hallucination measurement, and differential privacy.
    """
    if verbose:
        click.echo("Verbose mode enabled")


@cli.command()
@click.option('--model', '-m', help='Model name or identifier (e.g., gpt-3.5-turbo)')
@click.option('--input', '-i', help='Single input text to evaluate')
@click.option('--dataset', '-d', type=click.Path(exists=True), help='Dataset file (JSON, CSV, or TXT)')
@click.option('--output', '-o', type=click.Path(), help='Output file path (JSON, CSV, or HTML)')
@click.option('--evaluators', '-e', default='hallucination,bias', 
              help='Comma-separated evaluators: hallucination,bias,toxicity,semantic')
@click.option('--ground-truth', '-g', help='Ground truth text or file path')
@click.option('--contexts', '-c', help='Context text or file path')
@click.option('--format', 'output_format', default='json', 
              type=click.Choice(['json', 'csv', 'html']), help='Output format')
@click.option('--max-samples', type=int, help='Maximum number of samples to evaluate')
def evaluate(model, input, dataset, output, evaluators, ground_truth, contexts, output_format, max_samples):
    """Run evaluation from command line.
    
    Examples:
        themis evaluate --input "The sky is blue" --evaluators hallucination,bias
        themis evaluate --model gpt-3.5-turbo --dataset data.json --output results.json
        themis evaluate --input "All women are bad drivers" --ground-truth "Driving ability varies by individual"
    """
    try:
        from themis import ThemisEvaluator, HallucinationDetector, BiasDetector, ToxicityDetector, SemanticSimilarity
        
        # Validate inputs
        if not input and not dataset:
            click.echo("Error: Either --input or --dataset must be provided")
            return
        
        # Parse evaluators
        evaluator_list = [e.strip() for e in evaluators.split(',')]
        
        # Initialize evaluator
        evaluator = ThemisEvaluator()
        
        # Add requested evaluators
        evaluator_map = {
            'hallucination': HallucinationDetector,
            'bias': BiasDetector,
            'toxicity': ToxicityDetector,
            'semantic': SemanticSimilarity
        }
        
        added_evaluators = []
        for eval_name in evaluator_list:
            if eval_name in evaluator_map:
                try:
                    eval_class = evaluator_map[eval_name]
                    if eval_class is not None:
                        evaluator.add_evaluator(eval_class())
                        added_evaluators.append(eval_name)
                    else:
                        click.echo(f"Warning: {eval_name} evaluator not available")
                except Exception as e:
                    click.echo(f"Warning: Could not add {eval_name} evaluator: {e}")
            else:
                click.echo(f"Warning: Unknown evaluator '{eval_name}'")
                click.echo("Available: hallucination, bias, toxicity, semantic")
        
        if not added_evaluators:
            click.echo("Error: No evaluators were successfully added")
            return
        
        # Prepare data
        if input:
            model_outputs = [input]
            ground_truth_data = [ground_truth] if ground_truth else None
            contexts_data = [contexts] if contexts else None
        else:
            # Load dataset
            model_outputs, ground_truth_data, contexts_data = load_dataset(
                dataset, ground_truth, contexts, max_samples
            )
        
        # Run evaluation
        click.echo(f"Running evaluation with: {', '.join(added_evaluators)}")
        if model:
            click.echo(f"Model: {model}")
        click.echo(f"Samples: {len(model_outputs)}")
        
        with click.progressbar(length=len(model_outputs), 
                             label='Evaluating') as bar:
            results = evaluator.evaluate(
                model_outputs=model_outputs,
                ground_truth=ground_truth_data,
                contexts=contexts_data
            )
            bar.update(len(model_outputs))
        
        # Display results
        display_results(results, model)
        
        # Save results if requested
        if output:
            save_results(results, output, output_format, model)
            click.echo(f"Results saved to: {output}")
        
    except Exception as e:
        click.echo(f"Error: {e}")
        if click.get_current_context().find_root().params.get('verbose'):
            import traceback
            traceback.print_exc()


@cli.command()
@click.option('--models', '-m', required=True, 
              help='Comma-separated model names (e.g., model1,model2,model3)')
@click.option('--dataset', '-d', type=click.Path(exists=True), required=True,
              help='Test dataset file')
@click.option('--evaluators', '-e', default='hallucination,bias',
              help='Evaluators to use for comparison')
@click.option('--baseline', help='Baseline model name (first model by default)')
@click.option('--output', '-o', type=click.Path(), help='Output comparison results')
@click.option('--statistical-test', default='welch_ttest',
              type=click.Choice(['welch_ttest', 'mann_whitney', 'permutation']),
              help='Statistical test for significance')
@click.option('--alpha', default=0.05, type=float, help='Significance level')
def compare(models, dataset, evaluators, baseline, output, statistical_test, alpha):
    """Compare multiple models using A/B testing.
    
    Examples:
        themis compare --models gpt-3.5-turbo,gpt-4,claude-3 --dataset test_data.json
        themis compare --models model1,model2 --evaluators hallucination,bias --baseline model1
    """
    try:
        from themis.testing import ModelComparison
        
        model_list = [m.strip() for m in models.split(',')]
        
        if len(model_list) < 2:
            click.echo("Error: At least 2 models required for comparison")
            return
        
        click.echo(f"Comparing {len(model_list)} models: {', '.join(model_list)}")
        
        # Load test data
        test_data, _, _ = load_dataset(dataset)
        
        # Initialize comparison
        comparison = ModelComparison()
        
        # Prepare models dictionary (placeholder - in real use would load actual models)
        models_dict = {name: name for name in model_list}  # Simplified for demo
        
        # Run comparison
        evaluator_list = [e.strip() for e in evaluators.split(',')]
        
        click.echo(f"Running comparison on {len(test_data)} test cases...")
        click.echo(f"Using evaluators: {', '.join(evaluator_list)}")
        
        results = comparison.compare_models(
            models=models_dict,
            test_cases=test_data,
            evaluators=evaluator_list,
            baseline_model=baseline
        )
        
        # Display comparison results
        display_comparison_results(results, model_list, statistical_test, alpha)
        
        # Save results
        if output:
            save_comparison_results(results, output)
            click.echo(f"Comparison results saved to: {output}")
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
@click.option('--results', '-r', type=click.Path(exists=True), required=True,
              help='Results file from evaluation')
@click.option('--output', '-o', type=click.Path(), help='Output report file')
@click.option('--format', 'report_format', default='html',
              type=click.Choice(['html', 'pdf', 'markdown']), help='Report format')
@click.option('--template', type=click.Path(exists=True), help='Custom report template')
@click.option('--include-charts', is_flag=True, help='Include visualization charts')
def report(results, output, report_format, template, include_charts):
    """Generate comprehensive evaluation report.
    
    Examples:
        themis report --results evaluation.json --format html
        themis report --results results.json --format pdf --include-charts
    """
    try:
        # Load results
        with open(results) as f:
            results_data = json.load(f)
        
        click.echo(f"Generating {report_format.upper()} report...")
        
        # Generate report content
        if report_format == 'html':
            report_content = generate_html_report(results_data, include_charts, template)
            extension = '.html'
        elif report_format == 'markdown':
            report_content = generate_markdown_report(results_data)
            extension = '.md'
        elif report_format == 'pdf':
            click.echo("PDF generation requires additional dependencies")
            report_content = generate_html_report(results_data, include_charts, template)
            extension = '.html'
        
        # Determine output path
        if output:
            output_path = Path(output)
        else:
            output_path = Path(results).with_suffix(extension)
        
        # Save report
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(report_content)
        
        click.echo(f"Report generated: {output_path}")
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
@click.option('--input', '-i', help='Input data to make private')
@click.option('--file', '-f', type=click.Path(exists=True), help='Input data file')
@click.option('--output', '-o', type=click.Path(), help='Output file for private data')
@click.option('--epsilon', '-eps', default=1.0, type=float, help='Privacy epsilon parameter')
@click.option('--delta', default=0.0, type=float, help='Privacy delta parameter')
@click.option('--mechanism', default='laplace',
              type=click.Choice(['laplace', 'gaussian']),
              help='Privacy mechanism to use')
@click.option('--sensitivity', default=1.0, type=float, help='Query sensitivity')
def privacy(input, file, output, epsilon, delta, mechanism, sensitivity):
    """Apply differential privacy to data.
    
    Examples:
        themis privacy --input "sensitive data" --epsilon 1.0 --mechanism laplace
        themis privacy --file sensitive_data.json --epsilon 0.5 --delta 1e-5 --mechanism gaussian
    """
    try:
        from themis.core.differential_privacy import LaplaceMechanism, GaussianMechanism
        
        # Prepare data
        if input:
            data = [input]
        elif file:
            data, _, _ = load_dataset(file)
        else:
            click.echo("Error: Either --input or --file must be provided")
            return
        
        # Initialize privacy mechanism
        if mechanism == 'laplace':
            privacy_mech = LaplaceMechanism(epsilon, delta)
        else:  # gaussian
            privacy_mech = GaussianMechanism(epsilon, delta)
        
        click.echo(f"Applying {mechanism} mechanism with epsilon={epsilon}, delta={delta}")
        
        # Apply privacy (simplified for demo)
        if isinstance(data[0], str):
            # For text data, apply to length as example
            lengths = [len(text) for text in data]
            private_lengths = privacy_mech.apply(lengths, sensitivity)
            
            click.echo(f"Original average length: {sum(lengths)/len(lengths):.2f}")
            click.echo(f"Private average length: {sum(private_lengths)/len(private_lengths):.2f}")
            
            private_data = {
                'original_sample': data[0] if len(data[0]) < 100 else data[0][:100] + "...",
                'private_lengths': private_lengths[:5],  # Show first 5
                'privacy_parameters': {
                    'epsilon': epsilon,
                    'delta': delta,
                    'mechanism': mechanism,
                    'sensitivity': sensitivity
                }
            }
        else:
            # Numerical data
            private_data = privacy_mech.apply(data, sensitivity)
        
        # Display or save results
        if output:
            with open(output, 'w') as f:
                json.dump(private_data, f, indent=2)
            click.echo(f"Private data saved to: {output}")
        else:
            click.echo("Privacy applied successfully")
            if isinstance(private_data, dict):
                for key, value in private_data.items():
                    if key != 'original_sample':
                        click.echo(f"  {key}: {value}")
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
@click.option('--input', '-i', help='Input text to analyze')
@click.option('--ground-truth', '-g', help='Ground truth for comparison')
def hallucination(input, ground_truth):
    """Quick hallucination detection.
    
    Example:
        themis hallucination --input "The Earth is flat" --ground-truth "The Earth is round"
    """
    if not input:
        click.echo("Error: Please provide input text with --input")
        return
    
    try:
        from themis import ThemisEvaluator, HallucinationDetector
        
        evaluator = ThemisEvaluator()
        evaluator.add_evaluator(HallucinationDetector())
        
        click.echo("Analyzing for hallucinations...")
        
        if ground_truth:
            results = evaluator.evaluate([input], [ground_truth])
        else:
            results = evaluator.evaluate([input])
        
        display_single_evaluator_results("Hallucination Detection", results)
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
@click.option('--input', '-i', help='Input text to analyze')
def bias(input):
    """Quick bias detection.
    
    Example:
        themis bias --input "All women are bad at mathematics"
    """
    if not input:
        click.echo("Error: Please provide input text with --input")
        return
    
    try:
        from themis import ThemisEvaluator, BiasDetector
        
        evaluator = ThemisEvaluator()
        evaluator.add_evaluator(BiasDetector())
        
        click.echo("Analyzing for bias...")
        
        results = evaluator.evaluate([input])
        display_single_evaluator_results("Bias Detection", results)
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
@click.option('--input', '-i', help='Input text to analyze')
def toxicity(input):
    """Quick toxicity detection.
    
    Example:
        themis toxicity --input "I hate everyone and want to hurt people"
    """
    if not input:
        click.echo("Error: Please provide input text with --input")
        return
    
    try:
        from themis import ThemisEvaluator, ToxicityDetector
        
        evaluator = ThemisEvaluator()
        evaluator.add_evaluator(ToxicityDetector())
        
        click.echo("Analyzing for toxicity...")
        
        results = evaluator.evaluate([input])
        display_single_evaluator_results("Toxicity Detection", results)
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
def demo():
    """Run comprehensive demonstration of Themis capabilities.
    
    Shows examples of bias detection, hallucination detection, and toxicity analysis.
    """
    try:
        from themis import ThemisEvaluator, HallucinationDetector, BiasDetector, ToxicityDetector
        
        click.echo("Themis AI Evaluation Framework Demo")
        click.echo("=" * 45)
        click.echo("Named after the Greek goddess of justice and divine order")
        click.echo("")
        
        # Demo test cases matching README examples
        test_cases = [
            {
                'text': 'The sky is blue and Paris is the capital of France.',
                'ground_truth': 'The sky is blue and Paris is the capital of France.',
                'description': 'Factual statement',
                'category': 'factual'
            },
            {
                'text': 'All women are naturally bad at mathematics and programming.',
                'ground_truth': 'Mathematical and programming abilities vary among individuals regardless of gender.',
                'description': 'Biased statement',
                'category': 'bias'
            },
            {
                'text': 'The Earth is flat and vaccines contain microchips for government tracking.',
                'ground_truth': 'The Earth is round and vaccines do not contain microchips.',
                'description': 'Hallucinated/false statement',
                'category': 'hallucination'
            },
            {
                'text': 'I hate all people from that country and they should be eliminated.',
                'ground_truth': 'People should be treated with respect regardless of their origin.',
                'description': 'Toxic statement',
                'category': 'toxicity'
            }
        ]
        
        evaluator = ThemisEvaluator()
        evaluator.add_evaluator(HallucinationDetector())
        evaluator.add_evaluator(BiasDetector())
        evaluator.add_evaluator(ToxicityDetector())
        
        for i, test_case in enumerate(test_cases, 1):
            click.echo(f"Test Case {i}: {test_case['description']}")
            click.echo(f"Text: '{test_case['text']}'")
            click.echo("-" * 60)
            
            results = evaluator.evaluate([test_case['text']], [test_case['ground_truth']])
            
            for result in results.results:
                if result.success:
                    click.echo(f"{result.evaluator_name}:")
                    for metric, value in result.metrics.items():
                        if isinstance(value, float):
                            if 'score' in metric or 'rate' in metric:
                                status = get_status_indicator(value, result.evaluator_name)
                                click.echo(f"   {metric}: {value:.3f} {status}")
                            else:
                                click.echo(f"   {metric}: {value:.3f}")
                        elif isinstance(value, (int, str)) and not isinstance(value, list):
                            click.echo(f"   {metric}: {value}")
                else:
                    click.echo(f"{result.evaluator_name}: FAILED")
            
            click.echo("")
        
        click.echo("Demo Summary:")
        click.echo("* Hallucination Detection: Identifies factually incorrect statements")
        click.echo("* Bias Detection: Measures various forms of bias and stereotypes")
        click.echo("* Toxicity Detection: Flags harmful and toxic content")
        click.echo("* Statistical Analysis: Provides quantitative metrics for each evaluation")
        click.echo("")
        click.echo("Try individual evaluations:")
        click.echo("   themis bias --input 'Your text here'")
        click.echo("   themis hallucination --input 'Your text' --ground-truth 'Truth'")
        click.echo("   themis toxicity --input 'Your text here'")
        
    except Exception as e:
        click.echo(f"Error: {e}")


@cli.command()
def version():
    """Show detailed version and system information."""
    try:
        import themis
        import sys
        import platform
        
        click.echo("Themis AI Evaluation Framework")
        click.echo("=" * 35)
        click.echo(f"Version: {themis.__version__}")
        click.echo(f"Author: {themis.__author__}")
        click.echo(f"Python: {sys.version.split()[0]}")
        click.echo(f"Platform: {platform.system()} {platform.release()}")
        click.echo("")
        click.echo("Links:")
        click.echo("   Documentation: https://themis-ai.readthedocs.io/")
        click.echo("   GitHub: https://github.com/themis-ai/themis")
        click.echo("   PyPI: https://pypi.org/project/themis-ai-eval/")
        
    except Exception as e:
        click.echo(f"Error: {e}")


# Helper functions
def load_dataset(dataset_path, ground_truth=None, contexts=None, max_samples=None):
    """Load dataset from file."""
    import json
    
    try:
        with open(dataset_path, encoding='utf-8') as f:
            if dataset_path.endswith('.json'):
                data = json.load(f)
                if isinstance(data, dict):
                    model_outputs = data.get('outputs', data.get('texts', data.get('data', [])))
                    ground_truth_data = data.get('ground_truth', data.get('targets', []))
                    contexts_data = data.get('contexts', [])
                else:
                    model_outputs = data
                    ground_truth_data = []
                    contexts_data = []
            else:
                # Plain text file
                model_outputs = f.read().strip().split('\n')
                ground_truth_data = []
                contexts_data = []
        
        if max_samples:
            model_outputs = model_outputs[:max_samples]
            if ground_truth_data:
                ground_truth_data = ground_truth_data[:max_samples]
            if contexts_data:
                contexts_data = contexts_data[:max_samples]
        
        return (
            model_outputs,
            ground_truth_data if ground_truth_data else None,
            contexts_data if contexts_data else None
        )
    
    except Exception as e:
        click.echo(f"Error loading dataset: {e}")
        return [], None, None


def display_results(results, model_name=None):
    """Display evaluation results."""
    click.echo("\nEvaluation Results")
    click.echo("=" * 25)
    
    if model_name:
        click.echo(f"Model: {model_name}")
    
    summary = results.summary()
    click.echo(f"Total evaluations: {summary['total_evaluations']}")
    click.echo(f"Success rate: {summary['success_rate']:.1%}")
    click.echo("")
    
    for result in results.results:
        if result.success:
            click.echo(f"{result.evaluator_name}:")
            for metric, value in result.metrics.items():
                if isinstance(value, float):
                    if 'score' in metric or 'rate' in metric:
                        status = get_status_indicator(value, result.evaluator_name)
                        click.echo(f"   {metric}: {value:.3f} {status}")
                    else:
                        click.echo(f"   {metric}: {value:.3f}")
                elif isinstance(value, (int, str)) and not isinstance(value, list):
                    click.echo(f"   {metric}: {value}")
            click.echo("")


def display_single_evaluator_results(title, results):
    """Display results for a single evaluator."""
    click.echo(f"\n{title} Results")
    click.echo("=" * (len(title) + 10))
    
    for result in results.results:
        if result.success:
            for metric, value in result.metrics.items():
                if isinstance(value, float):
                    if 'score' in metric or 'rate' in metric:
                        status = get_status_indicator(value, result.evaluator_name)
                        click.echo(f"{metric}: {value:.3f} {status}")
                    else:
                        click.echo(f"{metric}: {value:.3f}")
                elif isinstance(value, (int, str)) and not isinstance(value, list):
                    click.echo(f"{metric}: {value}")


def get_status_indicator(value, evaluator_name):
    """Get status indicator based on value and evaluator type."""
    if 'bias' in evaluator_name.lower():
        if value < 0.3:
            return "[Low bias]"
        elif value < 0.7:
            return "[Moderate bias]"
        else:
            return "[High bias]"
    elif 'hallucination' in evaluator_name.lower():
        if 'accuracy' in str(value) or value > 0.7:
            return "[Good accuracy]"
        elif value > 0.4:
            return "[Moderate accuracy]"
        else:
            return "[Low accuracy]"
    elif 'toxicity' in evaluator_name.lower():
        if value < 0.3:
            return "[Low toxicity]"
        elif value < 0.7:
            return "[Moderate toxicity]"
        else:
            return "[High toxicity]"
    return ""


def display_comparison_results(results, models, test_type, alpha):
    """Display model comparison results."""
    click.echo("\nModel Comparison Results")
    click.echo("=" * 30)
    click.echo(f"Models compared: {', '.join(models)}")
    click.echo(f"Statistical test: {test_type}")
    click.echo(f"Significance level: {alpha}")
    click.echo("\n(Note: Full statistical comparison requires actual model implementations)")


def save_results(results, output_path, format, model_name=None):
    """Save evaluation results to file."""
    output_data = {
        'model': model_name,
        'results': results.to_dict(),
        'summary': results.summary()
    }
    
    if format == 'json':
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(output_data, f, indent=2)
    # Add other formats as needed


def save_comparison_results(results, output_path):
    """Save comparison results."""
    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(results, f, indent=2, default=str)


def generate_html_report(results_data, include_charts=False, template=None):
    """Generate HTML report."""
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>Themis Evaluation Report</title>
        <style>
            body {{ font-family: Arial, sans-serif; margin: 40px; }}
            .header {{ color: #2c3e50; border-bottom: 2px solid #3498db; }}
            .metric {{ margin: 10px 0; padding: 5px; background: #f8f9fa; }}
            .success {{ color: #27ae60; }}
            .warning {{ color: #f39c12; }}
            .error {{ color: #e74c3c; }}
        </style>
    </head>
    <body>
        <h1 class="header">Themis Evaluation Report</h1>
        <h2>Results Summary</h2>
        <div class="metric">
            <strong>Evaluation Data:</strong> {results_data}
        </div>
        <p><em>Generated by Themis AI Evaluation Framework</em></p>
    </body>
    </html>
    """
    return html


def generate_markdown_report(results_data):
    """Generate Markdown report."""
    return f"""# Themis Evaluation Report

## Results Summary

```json
{json.dumps(results_data, indent=2)}
```

*Generated by Themis AI Evaluation Framework*
"""


def main():
    """Main entry point."""
    cli()


if __name__ == '__main__':
    main()
