#!/usr/bin/env python3
"""
Configuration Validation CLI for NFOGuard
Provides command-line validation and reporting of configuration issues
"""
import sys
import json
import argparse
from pathlib import Path
from typing import Dict, Any, List
from datetime import datetime

from config.validator import validate_configuration, ValidationSeverity
from config.runtime_validator import RuntimeValidator
from config.settings import NFOGuardConfig


class ValidationReporter:
    """Formats and displays validation results"""
    
    def __init__(self, verbose: bool = False, json_output: bool = False):
        self.verbose = verbose
        self.json_output = json_output
        
        # Color codes for terminal output
        self.colors = {
            'error': '\033[91m',    # Red
            'warning': '\033[93m',  # Yellow
            'info': '\033[94m',     # Blue
            'success': '\033[92m',  # Green
            'reset': '\033[0m',     # Reset
            'bold': '\033[1m'       # Bold
        }
    
    def report_validation_results(self, result, runtime_result=None) -> int:
        """
        Report validation results
        
        Returns:
            Exit code (0 for success, 1 for warnings, 2 for errors)
        """
        if self.json_output:
            return self._report_json(result, runtime_result)
        else:
            return self._report_human_readable(result, runtime_result)
    
    def _report_json(self, result, runtime_result=None) -> int:
        """Report results in JSON format"""
        output = {
            "timestamp": datetime.now().isoformat(),
            "validation": result.to_dict()
        }
        
        if runtime_result:
            output["runtime_validation"] = runtime_result.to_dict()
        
        print(json.dumps(output, indent=2))
        
        if result.errors_count > 0:
            return 2
        elif result.warnings_count > 0:
            return 1
        return 0
    
    def _report_human_readable(self, result, runtime_result=None) -> int:
        """Report results in human-readable format"""
        print(f"{self.colors['bold']}NFOGuard Configuration Validation Report{self.colors['reset']}")
        print("=" * 50)
        
        # Overall status
        if result.is_valid:
            status_color = self.colors['success']
            status_text = "✓ VALID"
        else:
            status_color = self.colors['error']
            status_text = "✗ INVALID"
        
        print(f"Status: {status_color}{status_text}{self.colors['reset']}")
        print(f"Errors: {result.errors_count}")
        print(f"Warnings: {result.warnings_count}")
        print(f"Total Issues: {len(result.issues)}")
        print()
        
        # Report issues by severity
        if result.issues:
            self._report_issues_by_severity(result.issues)
        
        # Report runtime validation if available
        if runtime_result:
            print(f"\n{self.colors['bold']}Runtime Validation{self.colors['reset']}")
            print("-" * 20)
            if runtime_result.issues:
                self._report_issues_by_severity(runtime_result.issues, "Runtime")
            else:
                print(f"{self.colors['success']}✓ All runtime checks passed{self.colors['reset']}")
        
        # Summary and recommendations
        self._report_summary_and_recommendations(result)
        
        # Return appropriate exit code
        if result.errors_count > 0 or (runtime_result and runtime_result.errors_count > 0):
            return 2
        elif result.warnings_count > 0 or (runtime_result and runtime_result.warnings_count > 0):
            return 1
        return 0
    
    def _report_issues_by_severity(self, issues: List, context: str = "Configuration") -> None:
        """Report issues grouped by severity"""
        errors = [issue for issue in issues if issue.severity == ValidationSeverity.ERROR]
        warnings = [issue for issue in issues if issue.severity == ValidationSeverity.WARNING]
        info_issues = [issue for issue in issues if issue.severity == ValidationSeverity.INFO]
        
        if errors:
            print(f"{self.colors['error']}{self.colors['bold']}ERRORS ({len(errors)}):{self.colors['reset']}")
            for issue in errors:
                self._format_issue(issue)
            print()
        
        if warnings:
            print(f"{self.colors['warning']}{self.colors['bold']}WARNINGS ({len(warnings)}):{self.colors['reset']}")
            for issue in warnings:
                self._format_issue(issue)
            print()
        
        if info_issues and self.verbose:
            print(f"{self.colors['info']}{self.colors['bold']}INFO ({len(info_issues)}):{self.colors['reset']}")
            for issue in info_issues:
                self._format_issue(issue)
            print()
    
    def _format_issue(self, issue) -> None:
        """Format a single validation issue"""
        severity_colors = {
            ValidationSeverity.ERROR: self.colors['error'],
            ValidationSeverity.WARNING: self.colors['warning'],
            ValidationSeverity.INFO: self.colors['info']
        }
        
        color = severity_colors.get(issue.severity, '')
        
        print(f"  {color}• {issue.setting}:{self.colors['reset']} {issue.message}")
        
        if issue.current_value is not None:
            print(f"    Current: {issue.current_value}")
        
        if issue.suggested_value is not None:
            print(f"    Suggested: {issue.suggested_value}")
        
        if self.verbose and issue.details:
            print(f"    Details: {issue.details}")
    
    def _report_summary_and_recommendations(self, result) -> None:
        """Report summary and general recommendations"""
        print(f"\n{self.colors['bold']}Summary{self.colors['reset']}")
        print("-" * 10)
        
        if result.is_valid:
            print(f"{self.colors['success']}✓ Your configuration is valid and ready to use!{self.colors['reset']}")
        else:
            print(f"{self.colors['error']}✗ Your configuration has issues that need to be resolved.{self.colors['reset']}")
        
        # Provide specific recommendations based on issue types
        recommendations = self._generate_recommendations(result)
        if recommendations:
            print(f"\n{self.colors['bold']}Recommendations{self.colors['reset']}")
            print("-" * 15)
            for rec in recommendations:
                print(f"  {self.colors['info']}• {rec}{self.colors['reset']}")
    
    def _generate_recommendations(self, result) -> List[str]:
        """Generate recommendations based on validation results"""
        recommendations = []
        
        # Check for common patterns
        path_issues = [issue for issue in result.issues if 'path' in issue.setting.lower()]
        if path_issues:
            recommendations.append("Verify all file paths are correct for your environment")
            recommendations.append("Ensure paths are absolute when using Docker")
        
        db_issues = [issue for issue in result.issues if 'db' in issue.setting.lower()]
        if db_issues:
            recommendations.append("Check database connection settings and credentials")
        
        url_issues = [issue for issue in result.issues if 'url' in issue.setting.lower()]
        if url_issues:
            recommendations.append("Verify API URLs are reachable and include the correct port")
        
        perf_issues = [issue for issue in result.issues if any(perf in issue.setting.lower() 
                      for perf in ['concurrent', 'delay', 'timeout'])]
        if perf_issues:
            recommendations.append("Consider adjusting performance settings based on your system resources")
        
        # General recommendations
        if result.errors_count > 0:
            recommendations.append("Fix all ERROR-level issues before starting NFOGuard")
        
        if result.warnings_count > 0:
            recommendations.append("Review WARNING-level issues to optimize performance and reliability")
        
        return recommendations


async def run_validation(args) -> int:
    """Run configuration validation"""
    reporter = ValidationReporter(verbose=args.verbose, json_output=args.json)
    
    try:
        # Run static validation
        print("Running configuration validation..." if not args.json else "", file=sys.stderr)
        result = validate_configuration()
        
        runtime_result = None
        
        # Run runtime validation if requested
        if args.runtime:
            print("Running runtime validation..." if not args.json else "", file=sys.stderr)
            try:
                config = NFOGuardConfig()
                runtime_validator = RuntimeValidator(config)
                runtime_result = await runtime_validator.validate_runtime_config()
            except Exception as e:
                if not args.json:
                    print(f"Runtime validation failed: {e}", file=sys.stderr)
                # Continue with static validation results
        
        # Report results
        return reporter.report_validation_results(result, runtime_result)
        
    except Exception as e:
        if args.json:
            error_output = {
                "timestamp": datetime.now().isoformat(),
                "error": {
                    "message": str(e),
                    "type": type(e).__name__
                }
            }
            print(json.dumps(error_output, indent=2))
        else:
            print(f"Validation failed: {e}", file=sys.stderr)
        return 2


def main():
    """Main CLI entry point"""
    parser = argparse.ArgumentParser(
        description="Validate NFOGuard configuration",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s                    # Basic validation
  %(prog)s --runtime          # Include runtime checks
  %(prog)s --verbose          # Show detailed information
  %(prog)s --json             # Output JSON format
  %(prog)s --runtime --json   # Runtime validation with JSON output
        """
    )
    
    parser.add_argument(
        "--runtime",
        action="store_true",
        help="Perform runtime validation (tests actual connectivity and permissions)"
    )
    
    parser.add_argument(
        "--verbose", "-v",
        action="store_true",
        help="Show verbose output including info-level messages"
    )
    
    parser.add_argument(
        "--json",
        action="store_true",
        help="Output results in JSON format"
    )
    
    args = parser.parse_args()
    
    # Run validation
    import asyncio
    try:
        exit_code = asyncio.run(run_validation(args))
        sys.exit(exit_code)
    except KeyboardInterrupt:
        print("Validation interrupted", file=sys.stderr)
        sys.exit(130)
    except Exception as e:
        print(f"Unexpected error: {e}", file=sys.stderr)
        sys.exit(2)


if __name__ == "__main__":
    main()