"""
Main entry point for the Ethernet Traffic Analyzer
"""

import sys
import time
import threading
import argparse
import curses

from .analysis import EthernetAnalyzer
from .tui import TUIInterface
from .tui.modern_interface import ModernTUIInterface
from .tui.textual.app_v2 import StreamLensAppV2
from .utils import PCAPLoader, LiveCapture
from .reporting import FlowReportGenerator


def main():
    """Main entry point"""
    parser = argparse.ArgumentParser(description='Ethernet Traffic Analyzer')
    parser.add_argument('--pcap', '-p', help='PCAP file to analyze')
    parser.add_argument('--live', '-l', action='store_true', help='Start live capture')
    parser.add_argument('--interface', '-i', help='Network interface for live capture')
    parser.add_argument('--filter', '-f', help='BPF filter for live capture')
    parser.add_argument('--no-tui', action='store_true', help='Disable TUI, print to console')
    parser.add_argument('--info', action='store_true', help='Show PCAP file information only')
    parser.add_argument('--outlier-threshold', type=float, default=3.0, 
                       help='Outlier detection threshold in standard deviations (default: 3.0)')
    parser.add_argument('--report', action='store_true', 
                       help='Generate comprehensive outlier report and exit (no TUI)')
    parser.add_argument('--flow-report', metavar='OUTPUT_FILE',
                       help='Generate comprehensive flow analysis report to specified file and exit')
    parser.add_argument('--report-format', choices=['markdown', 'html', 'text'], default='markdown',
                       help='Report output format (default: markdown)')
    parser.add_argument('--gui', action='store_true', 
                       help='Launch GUI mode (requires PySide6)')
    parser.add_argument('--classic', action='store_true',
                       help='Use classic TUI interface')
    parser.add_argument('--textual', action='store_true',
                       help='Use modern Textual TUI interface (experimental)')
    
    args = parser.parse_args()
    
    # Handle GUI mode
    if args.gui:
        launch_gui(args)
        return
    
    if not args.pcap and not args.live:
        print("Error: Must specify either --pcap file or --live capture")
        sys.exit(1)
    
    # Create analyzer - enable real-time stats for live capture
    enable_realtime = args.live
    analyzer = EthernetAnalyzer(enable_realtime=enable_realtime, outlier_threshold_sigma=args.outlier_threshold)
    
    # Handle PCAP info mode
    if args.info and args.pcap:
        print("Analyzing PCAP file information...")
        info = PCAPLoader.get_file_info(args.pcap)
        if 'error' in info:
            print(f"Error: {info['error']}")
            sys.exit(1)
        
        print(f"\n=== PCAP FILE INFORMATION ===")
        print(f"File: {info['file_path']}")
        print(f"Packets: {info['packet_count']:,}")
        print(f"Total bytes: {info['total_bytes']:,}")
        print(f"Duration: {info['duration_seconds']:.2f} seconds")
        print(f"Average packet rate: {info['avg_packet_rate']:.1f} packets/sec")
        if info['first_timestamp']:
            import datetime
            first_time = datetime.datetime.fromtimestamp(info['first_timestamp'])
            last_time = datetime.datetime.fromtimestamp(info['last_timestamp'])
            print(f"First packet: {first_time}")
            print(f"Last packet: {last_time}")
        return
    
    # Load PCAP file (skip for textual mode which uses background parsing)
    if args.pcap and not args.textual:
        try:
            loader = PCAPLoader(args.pcap)
            if not loader.validate_file():
                print(f"Error: Invalid or inaccessible PCAP file: {args.pcap}")
                sys.exit(1)
            
            packets = loader.load_all()
            analyzer.all_packets = packets
            print(f"Loaded {len(packets)} packets")
            
            # Process packets
            for i, packet in enumerate(packets, 1):
                analyzer._process_single_packet(packet, i)
            
            analyzer.calculate_statistics()
            
        except Exception as e:
            print(f"Error loading PCAP file: {e}")
            sys.exit(1)
    elif args.pcap and args.textual:
        # For textual mode, just validate the file exists
        try:
            loader = PCAPLoader(args.pcap)
            if not loader.validate_file():
                print(f"Error: Invalid or inaccessible PCAP file: {args.pcap}")
                sys.exit(1)
        except Exception as e:
            print(f"Error validating PCAP file: {e}")
            sys.exit(1)
    
    # Handle console output mode
    if args.no_tui:
        print_console_results(analyzer)
        return
    
    # Handle report mode
    if args.report:
        generate_outlier_report(analyzer, args.outlier_threshold)
        return
    
    # Handle flow report mode
    if args.flow_report:
        generate_flow_report(analyzer, args.flow_report, args.report_format)
        return
    
    # TUI mode - choose between classic, modern curses, and textual interface
    if args.textual:
        # Use new Textual-based interface (TipTop-inspired) with background parsing
        app = StreamLensAppV2(analyzer)
        
        try:
            # Start background parsing if PCAP file provided
            if args.pcap:
                app.start_background_parsing(args.pcap)
            
            app.run()
        except KeyboardInterrupt:
            print("\nShutting down...")
        finally:
            # Cleanup background threads
            try:
                app.cleanup()
            except Exception as e:
                print(f"Cleanup error: {e}")
                pass
        return
    elif args.classic:
        tui = TUIInterface(analyzer)
    else:
        tui = ModernTUIInterface(analyzer)
    
    if args.live:
        # Start live capture
        capture = LiveCapture(args.interface, args.filter)
        
        def packet_handler(packet, frame_num):
            analyzer.all_packets.append(packet)
            analyzer._process_single_packet(packet, frame_num)
        
        capture.add_packet_handler(packet_handler)
        
        try:
            capture.start_capture(threaded=True)
            analyzer.is_live = True
            
            print("Starting live capture with real-time statistics enabled...")
            print("TUI will update every 0.5 seconds with running averages and outlier detection")
            
            # Give capture a moment to start
            time.sleep(1)
            
            # Run TUI with error handling
            try:
                curses.wrapper(tui.run)
            except curses.error as e:
                print(f"\nTUI error: {e}")
                print("Falling back to console mode...")
                print_console_results(analyzer)
            
        except KeyboardInterrupt:
            print("\nCapture interrupted by user")
        finally:
            capture.stop_capture()
    else:
        # PCAP analysis mode
        try:
            try:
                curses.wrapper(tui.run)
            except curses.error as e:
                print(f"\nTUI error: {e}")
                print("Terminal doesn't support curses. Falling back to console mode...")
                print_console_results(analyzer)
        except KeyboardInterrupt:
            print("\nAnalysis interrupted by user")


def print_console_results(analyzer: EthernetAnalyzer):
    """Print analysis results to console"""
    summary = analyzer.get_summary() 
    
    print(f"\n=== ETHERNET TRAFFIC ANALYSIS RESULTS ===")
    print(f"Total Packets: {summary['total_packets']}")
    print(f"Unique IP Flows: {summary['unique_flows']}")
    print(f"Unique IP Addresses: {summary['unique_ips']}")
    
    # Show summary statistics
    stats = analyzer.get_summary_statistics()
    if stats:
        print(f"\n=== SUMMARY STATISTICS ===")
        print(f"Overall Avg Inter-arrival: {stats.get('overall_avg_inter_arrival', 0):.6f}s")
        print(f"Overall Std Deviation: {stats.get('overall_std_inter_arrival', 0):.6f}s")
        print(f"Total Outliers: {stats.get('total_outliers', 0)}")
        print(f"Outlier Percentage: {stats.get('outlier_percentage', 0):.2f}%")
    
    # Show real-time statistics if enabled
    if analyzer.statistics_engine.enable_realtime:
        rt_stats = analyzer.statistics_engine.get_realtime_summary()
        if rt_stats:
            print(f"\n=== REAL-TIME STATISTICS ===")
            print(f"Real-time Mode: {rt_stats.get('realtime_enabled', False)}")
            print(f"Tracked Flows: {rt_stats.get('tracked_flows', 0)}")
            print(f"Update Frequency: {rt_stats.get('update_frequency', 'N/A')}")
    
    print(f"\n=== FLOW STATISTICS ===")
    flows_sorted = sorted(summary['flows'].values(), key=lambda x: (
        analyzer.statistics_engine.get_max_sigma_deviation(x), 
        x.frame_count
    ), reverse=True)
    
    for flow in flows_sorted:
        max_sigma = analyzer.statistics_engine.get_max_sigma_deviation(flow)
        print(f"\nFlow: {flow.src_ip} -> {flow.dst_ip}")
        print(f"  Packets: {flow.frame_count}")
        print(f"  Total Bytes: {flow.total_bytes:,}")
        print(f"  Max Sigma Deviation: {max_sigma:.2f}σ")
        print(f"  Protocols: {', '.join(flow.protocols)}")
        if flow.detected_protocol_types:
            print(f"  Enhanced Protocols: {', '.join(flow.detected_protocol_types)}")
        
        if flow.avg_inter_arrival > 0:
            print(f"  Avg Inter-arrival: {flow.avg_inter_arrival:.6f}s")
            print(f"  Std Deviation: {flow.std_inter_arrival:.6f}s")
        
        if flow.outlier_frames:
            print(f"  Outlier Frames: {flow.outlier_frames}")
        
        # Show frame type breakdown
        if flow.frame_types:
            print(f"  Frame Types:")
            for frame_type, ft_stats in flow.frame_types.items():
                avg_str = f"{ft_stats.avg_inter_arrival:.3f}s" if ft_stats.avg_inter_arrival > 0 else "N/A"
                print(f"    {frame_type}: {ft_stats.count} packets, avg {avg_str}")
    
    # Show high jitter flows
    high_jitter = analyzer.get_high_jitter_flows()
    if high_jitter:
        print(f"\n=== HIGH JITTER FLOWS ===")
        for flow in high_jitter[:5]:  # Show top 5
            cv = flow.std_inter_arrival / flow.avg_inter_arrival if flow.avg_inter_arrival > 0 else 0
            print(f"{flow.src_ip} -> {flow.dst_ip}: CV = {cv:.3f}")


def generate_flow_report(analyzer: EthernetAnalyzer, output_file: str, format_type: str):
    """Generate comprehensive flow analysis report"""
    print(f"Generating {format_type} flow analysis report...")
    
    try:
        # Create report generator
        report_generator = FlowReportGenerator(analyzer)
        
        # Generate report
        report_content = report_generator.generate_report(output_file, format_type)
        
        print(f"✅ Flow analysis report generated successfully!")
        print(f"📄 Output file: {output_file}")
        print(f"📊 Format: {format_type}")
        print(f"📈 Flows analyzed: {len(analyzer.flows)}")
        
        # Show preview of report length
        lines = report_content.count('\n')
        print(f"📝 Report length: {lines} lines")
        
    except Exception as e:
        print(f"❌ Error generating flow report: {e}")
        sys.exit(1)


def generate_outlier_report(analyzer: EthernetAnalyzer, threshold_sigma: float):
    """Generate comprehensive outlier report without TUI"""
    summary = analyzer.get_summary()
    
    print("=" * 80)
    print("COMPREHENSIVE OUTLIER ANALYSIS REPORT")
    print("=" * 80)
    
    # Analysis parameters
    print(f"Outlier Detection Threshold: {threshold_sigma}σ (sigma)")
    print(f"Total Packets Analyzed: {summary['total_packets']:,}")
    print(f"Unique IP Flows: {summary['unique_flows']}")
    print(f"Unique IP Addresses: {summary['unique_ips']}")
    
    # Overall statistics
    stats = analyzer.get_summary_statistics()
    if stats:
        print(f"\nOVERALL TIMING STATISTICS:")
        print(f"  Average Inter-arrival Time: {stats.get('overall_avg_inter_arrival', 0):.6f}s")
        print(f"  Standard Deviation: {stats.get('overall_std_inter_arrival', 0):.6f}s")
        print(f"  Total Outlier Frames: {stats.get('total_outliers', 0)}")
        print(f"  Outlier Percentage: {stats.get('outlier_percentage', 0):.2f}%")
    
    print("\n" + "=" * 80)
    print("DETAILED FLOW ANALYSIS")
    print("=" * 80)
    
    flows_sorted = sorted(summary['flows'].values(), key=lambda x: (
        analyzer.statistics_engine.get_max_sigma_deviation(x), 
        x.frame_count
    ), reverse=True)
    
    for flow_idx, flow in enumerate(flows_sorted, 1):
        max_sigma = analyzer.statistics_engine.get_max_sigma_deviation(flow)
        print(f"\n[FLOW {flow_idx}] {flow.src_ip} -> {flow.dst_ip}")
        print("-" * 60)
        
        # Flow summary
        print(f"Total Packets: {flow.frame_count:,}")
        print(f"Total Bytes: {flow.total_bytes:,}")
        print(f"Max Sigma Deviation: {max_sigma:.2f}σ")
        print(f"Protocols: {', '.join(flow.protocols)}")
        if flow.detected_protocol_types:
            print(f"Enhanced Protocols: {', '.join(flow.detected_protocol_types)}")
        
        # Flow timing statistics
        if flow.avg_inter_arrival > 0:
            print(f"Flow Timing:")
            print(f"  Average Inter-arrival: {flow.avg_inter_arrival:.6f}s")
            print(f"  Standard Deviation: {flow.std_inter_arrival:.6f}s")
            print(f"  Outlier Threshold: {flow.avg_inter_arrival + (threshold_sigma * flow.std_inter_arrival):.6f}s")
            print(f"  Flow-level Outliers: {len(flow.outlier_details)}")
        
        # Frame type analysis
        if flow.frame_types:
            print(f"\nFrame Type Breakdown:")
            print(f"  {'Type':<15} {'Count':<8} {'Avg ΔT':<12} {'Std Dev':<12} {'Out':<6} {'Out %':<8}")
            print(f"  {'-' * 15} {'-' * 8} {'-' * 12} {'-' * 12} {'-' * 6} {'-' * 8}")
            
            sorted_frame_types = sorted(flow.frame_types.items(), 
                                      key=lambda x: x[1].count, reverse=True)
            
            for frame_type, ft_stats in sorted_frame_types:
                outlier_count = len(ft_stats.outlier_details)
                outlier_pct = (outlier_count / ft_stats.count * 100) if ft_stats.count > 0 else 0
                
                avg_str = f"{ft_stats.avg_inter_arrival:.6f}s" if ft_stats.avg_inter_arrival > 0 else "N/A"
                std_str = f"{ft_stats.std_inter_arrival:.6f}s" if ft_stats.std_inter_arrival > 0 else "N/A"
                
                print(f"  {frame_type:<15} {ft_stats.count:<8} {avg_str:<12} {std_str:<12} {outlier_count:<6} {outlier_pct:<7.1f}%")
        
        # Detailed outlier frames
        has_outliers = any(ft_stats.outlier_details for ft_stats in flow.frame_types.values())
        
        if has_outliers:
            print(f"\nOutlier Frame Details:")
            for frame_type, ft_stats in flow.frame_types.items():
                if ft_stats.outlier_details:
                    print(f"\n  {frame_type} Outliers ({len(ft_stats.outlier_details)} frames):")
                    if ft_stats.avg_inter_arrival > 0:
                        threshold = ft_stats.avg_inter_arrival + (threshold_sigma * ft_stats.std_inter_arrival)
                        print(f"    Threshold: {threshold:.6f}s (>{threshold_sigma}σ from mean {ft_stats.avg_inter_arrival:.6f}s)")
                    
                    # Use enhanced outlier details if available
                    if hasattr(ft_stats, 'enhanced_outlier_details') and ft_stats.enhanced_outlier_details:
                        print(f"    {'Frame#':<10} {'From Frame':<10} {'Inter-arrival':<15} {'Deviation':<12}")
                        print(f"    {'-' * 10} {'-' * 10} {'-' * 15} {'-' * 12}")
                        
                        for frame_num, prev_frame_num, inter_arrival_time in ft_stats.enhanced_outlier_details:
                            if ft_stats.avg_inter_arrival > 0:
                                deviation = inter_arrival_time - ft_stats.avg_inter_arrival
                                sigma_dev = deviation / ft_stats.std_inter_arrival if ft_stats.std_inter_arrival > 0 else 0
                                dev_str = f"+{sigma_dev:.1f}σ"
                            else:
                                dev_str = "N/A"
                            
                            print(f"    {frame_num:<10} {prev_frame_num:<10} {inter_arrival_time:.6f}s{'':<3} {dev_str:<12}")
                    else:
                        # Fallback to legacy outlier details
                        print(f"    {'Frame#':<10} {'Inter-arrival':<15} {'Deviation':<12}")
                        print(f"    {'-' * 10} {'-' * 15} {'-' * 12}")
                        
                        for frame_num, inter_arrival_time in ft_stats.outlier_details:
                            if ft_stats.avg_inter_arrival > 0:
                                deviation = inter_arrival_time - ft_stats.avg_inter_arrival
                                sigma_dev = deviation / ft_stats.std_inter_arrival if ft_stats.std_inter_arrival > 0 else 0
                                dev_str = f"+{sigma_dev:.1f}σ"
                            else:
                                dev_str = "N/A"
                            
                            print(f"    {frame_num:<10} {inter_arrival_time:.6f}s{'':<3} {dev_str:<12}")
    
    # High jitter flows summary
    high_jitter = analyzer.get_high_jitter_flows()
    if high_jitter:
        print(f"\n" + "=" * 80)
        print("HIGH JITTER FLOWS (Coefficient of Variation > 0.1)")
        print("=" * 80)
        for flow in high_jitter[:10]:  # Show top 10
            cv = flow.std_inter_arrival / flow.avg_inter_arrival if flow.avg_inter_arrival > 0 else 0
            print(f"{flow.src_ip} -> {flow.dst_ip}: CV = {cv:.3f}")
    
    print(f"\n" + "=" * 80)
    print("REPORT COMPLETE")
    print("=" * 80)


def launch_gui(args):
    """Launch GUI mode"""
    try:
        from .gui import GUI_AVAILABLE, StreamLensMainWindow
        from PySide6.QtWidgets import QApplication
        
        if not GUI_AVAILABLE:
            print("Error: PySide6 not available. Please install with: pip install PySide6")
            sys.exit(1)
        
        # Create QApplication
        app = QApplication(sys.argv)
        app.setApplicationName("StreamLens")
        app.setApplicationDisplayName("StreamLens - Ethernet Traffic Analyzer")
        
        # Create main window
        window = StreamLensMainWindow()
        window.show()
        
        # If a PCAP file was specified, load it
        if args.pcap:
            window.load_pcap_file(args.pcap)
        
        # Start event loop
        sys.exit(app.exec())
        
    except ImportError as e:
        print(f"Error: GUI dependencies not available: {e}")
        print("Please install PySide6: pip install PySide6")
        sys.exit(1)
    except Exception as e:
        print(f"Error launching GUI: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()