"""
Advanced Traffic Analysis Module
Implements real-world traffic engineering metrics and per-road analysis
Based on Highway Capacity Manual (HCM), traffic flow theory, and academic research
"""

import math
import statistics
from typing import Dict, List, Tuple, Optional, Any
from dataclasses import dataclass
from enum import Enum

class LevelOfService(Enum):
    """Highway Capacity Manual Level of Service (LOS)"""
    A = "A"  # Free flow
    B = "B"  # Reasonably free flow
    C = "C"  # Stable flow
    D = "D"  # Approaching unstable flow
    E = "E"  # Unstable flow
    F = "F"  # Forced flow

@dataclass
class RoadMetrics:
    """Comprehensive metrics for a single road segment"""
    road_name: str
    road_length: float  # meters
    
    # Basic traffic counts
    vehicle_count: int
    total_vehicles_passed: int
    
    # Speed metrics (km/h)
    avg_speed: float
    median_speed: float
    speed_std: float
    speed_85th_percentile: float
    speed_15th_percentile: float
    speed_range: float
    
    # Flow metrics
    flow_rate: float  # vehicles per hour
    density: float    # vehicles per km
    occupancy: float  # percentage
    
    # Traffic flow theory metrics
    capacity: float   # theoretical capacity (veh/h)
    vc_ratio: float   # volume-to-capacity ratio
    level_of_service: LevelOfService
    
    # Congestion metrics
    delay_per_vehicle: float  # seconds
    total_delay: float        # vehicle-hours
    travel_time_index: float  # ratio of actual to free-flow time
    
    # Safety metrics
    speed_variance: float
    coefficient_of_variation: float
    speed_differential: float  # 85th - 15th percentile
    
    # Environmental metrics
    fuel_consumption_rate: float  # L/100km equivalent
    emissions_factor: float       # CO2 equivalent
    
    # Geometric factors
    lane_count: int
    road_width: float
    grade: float  # percentage
    
    # Temporal factors
    analysis_period: float  # seconds
    peak_hour_factor: float

@dataclass
class NetworkMetrics:
    """Network-wide traffic analysis metrics"""
    total_roads: int
    total_vehicles: int
    total_vehicle_miles: float
    
    # Network performance
    network_avg_speed: float
    network_delay: float
    network_efficiency: float
    
    # Congestion distribution
    congested_roads: int
    free_flow_roads: int
    
    # Safety indicators
    speed_violation_rate: float
    aggressive_driving_rate: float

class TrafficFlowTheory:
    """Implementation of traffic flow theory calculations"""
    
    @staticmethod
    def calculate_capacity(lane_count: int, road_type: str = "urban") -> float:
        """Calculate theoretical capacity based on HCM guidelines"""
        # Base capacity per lane (vehicles per hour)
        base_capacity = {
            "freeway": 2000,
            "arterial": 1800,
            "collector": 1500,
            "local": 1000,
            "urban": 1600
        }
        return base_capacity.get(road_type, 1600) * lane_count
    
    @staticmethod
    def calculate_level_of_service(vc_ratio: float, speed: float, road_type: str = "urban") -> LevelOfService:
        """Determine Level of Service based on HCM criteria"""
        if road_type == "freeway":
            if vc_ratio <= 0.35 and speed >= 100:
                return LevelOfService.A
            elif vc_ratio <= 0.50 and speed >= 90:
                return LevelOfService.B
            elif vc_ratio <= 0.70 and speed >= 75:
                return LevelOfService.C
            elif vc_ratio <= 0.90 and speed >= 60:
                return LevelOfService.D
            elif vc_ratio <= 1.00 and speed >= 45:
                return LevelOfService.E
            else:
                return LevelOfService.F
        else:  # Urban roads
            if vc_ratio <= 0.30 and speed >= 80:
                return LevelOfService.A
            elif vc_ratio <= 0.45 and speed >= 70:
                return LevelOfService.B
            elif vc_ratio <= 0.65 and speed >= 60:
                return LevelOfService.C
            elif vc_ratio <= 0.85 and speed >= 50:
                return LevelOfService.D
            elif vc_ratio <= 1.00 and speed >= 40:
                return LevelOfService.E
            else:
                return LevelOfService.F
    
    @staticmethod
    def calculate_density(flow_rate: float, avg_speed: float) -> float:
        """Calculate traffic density (vehicles per km)"""
        if avg_speed > 0:
            return flow_rate / avg_speed
        return 0.0
    
    @staticmethod
    def calculate_occupancy(vehicle_count: int, road_length: float, lane_count: int) -> float:
        """Calculate road occupancy percentage"""
        if road_length > 0 and lane_count > 0:
            # Average vehicle length ~4.5m
            vehicle_length = 4.5
            total_road_capacity = (road_length * lane_count) / vehicle_length
            return (vehicle_count / total_road_capacity) * 100
        return 0.0
    
    @staticmethod
    def calculate_travel_time_index(actual_time: float, free_flow_time: float) -> float:
        """Calculate travel time index (TTI)"""
        if free_flow_time > 0:
            return actual_time / free_flow_time
        return 1.0

class AdvancedTrafficAnalyzer:
    """Main traffic analysis engine with academic rigor"""
    
    def __init__(self, winRoadProxy, logProxy):
        self.winRoadProxy = winRoadProxy
        self.logProxy = logProxy
        self.road_metrics: Dict[str, RoadMetrics] = {}
        self.vehicle_history: Dict[str, List[Dict]] = {}  # road -> vehicle data history
        self.analysis_period = 60.0  # seconds
        self.fast_mode = False  # Fast analysis mode flag
        
    def analyze_road_network(self) -> Tuple[Dict[str, RoadMetrics], NetworkMetrics]:
        """Perform comprehensive analysis of the entire road network"""
        try:
            prj = self.winRoadProxy.Project
            traffic = self.winRoadProxy.ApplicationServices.SimulationCore.TrafficSimulation

            roads_count = getattr(prj, 'RoadsCount', 0)
            self.logProxy.logger.info(f"Analyzing {roads_count} roads in the network")

            # Get all vehicles in the area first for fallback analysis
            cam = self.winRoadProxy.MainForm.MainCamera
            center = cam.MainCameraState.eye
            all_vehicles = traffic.GetTransientVehiclesArround(1000, center)
            total_vehicles_in_area = getattr(all_vehicles, 'Count', 0)
            self.logProxy.logger.info(f"Found {total_vehicles_in_area} vehicles in analysis area")

            # Get all roads in the project
            road_metrics = {}
            total_vehicles = 0
            total_vehicle_miles = 0.0

            for i in range(roads_count):
                try:
                    road = prj.Road(i)
                    road_name = getattr(road, 'Name', f'Road_{i}')

                    # Debug: Log available attributes for first road
                    if i == 0:
                        available_attrs = [attr for attr in dir(road) if not attr.startswith('_')]
                        position_methods = [attr for attr in available_attrs if 'position' in attr.lower() or 'point' in attr.lower()]
                        self.logProxy.logger.info(f"Road {road_name} available attributes: {available_attrs[:15]}...")
                        self.logProxy.logger.info(f"Road {road_name} position-related methods: {position_methods}")
                        self.logProxy.logger.info(f"Road {road_name} has GetPositionAt: {hasattr(road, 'GetPositionAt')}")

                    self.logProxy.logger.info(f"Analyzing road {i+1}/{roads_count}: {road_name}")

                    # Analyze this road
                    metrics = self._analyze_single_road(road, traffic)
                    if metrics:
                        road_metrics[road_name] = metrics
                        total_vehicles += metrics.vehicle_count
                        total_vehicle_miles += metrics.vehicle_count * (metrics.road_length / 1000)
                        self.logProxy.logger.info(f"Road {road_name}: {metrics.vehicle_count} vehicles, {metrics.avg_speed:.1f} km/h avg speed")
                    else:
                        self.logProxy.logger.warning(f"Road {road_name}: No metrics generated")

                except Exception as road_e:
                    self.logProxy.logger.error(f"Failed to analyze road {i}: {road_e}")

            # If no roads were analyzed but we have vehicles, create a general area analysis
            if not road_metrics and total_vehicles_in_area > 0:
                self.logProxy.logger.info("No road-specific analysis succeeded, creating general area analysis")
                general_metrics = self._analyze_general_area(traffic, center, total_vehicles_in_area)
                if general_metrics:
                    road_metrics["General Area"] = general_metrics
                    total_vehicles = general_metrics.vehicle_count
                    total_vehicle_miles = general_metrics.vehicle_count * (general_metrics.road_length / 1000)

            self.logProxy.logger.info(f"Road analysis complete. Successfully analyzed {len(road_metrics)} roads/areas with vehicles")

            # Calculate network-wide metrics
            network_metrics = self._calculate_network_metrics(road_metrics, total_vehicles, total_vehicle_miles)

            self.road_metrics = road_metrics
            return road_metrics, network_metrics

        except Exception as e:
            self.logProxy.logger.error(f"analyze_road_network failed: {e}")
            return {}, NetworkMetrics(0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0)
    
    def _analyze_single_road(self, road, traffic) -> Optional[RoadMetrics]:
        """Analyze a single road segment with comprehensive metrics"""
        try:
            road_name = road.Name
            road_length = road.Length  # meters
            
            # Get vehicles on this road
            vehicles = self._get_vehicles_on_road(road, traffic)
            vehicle_count = len(vehicles)
            
            if vehicle_count == 0:
                return None
            
            # Calculate speed metrics
            speeds = [v['speed'] for v in vehicles if v['speed'] > 0]
            if not speeds:
                return None
                
            avg_speed = statistics.mean(speeds)
            median_speed = statistics.median(speeds)
            speed_std = statistics.stdev(speeds) if len(speeds) > 1 else 0.0
            
            # Calculate percentiles
            sorted_speeds = sorted(speeds)
            n = len(sorted_speeds)
            speed_85th = sorted_speeds[int(0.85 * n)] if n > 0 else avg_speed
            speed_15th = sorted_speeds[int(0.15 * n)] if n > 0 else avg_speed
            speed_range = max(speeds) - min(speeds)
            
            # Calculate flow metrics
            flow_rate = (vehicle_count / self.analysis_period) * 3600  # veh/h
            density = TrafficFlowTheory.calculate_density(flow_rate, avg_speed)
            
            # Estimate lane count (simplified)
            lane_count = max(1, int(road_length / 100))  # Rough estimate
            occupancy = TrafficFlowTheory.calculate_occupancy(vehicle_count, road_length, lane_count)
            
            # Calculate capacity and LOS
            capacity = TrafficFlowTheory.calculate_capacity(lane_count, "urban")
            vc_ratio = flow_rate / capacity if capacity > 0 else 0.0
            los = TrafficFlowTheory.calculate_level_of_service(vc_ratio, avg_speed, "urban")
            
            # Calculate delay and travel time metrics
            free_flow_speed = 60.0  # km/h assumed free flow
            free_flow_time = road_length / (free_flow_speed / 3.6)  # seconds
            actual_time = road_length / (avg_speed / 3.6) if avg_speed > 0 else free_flow_time
            delay_per_vehicle = max(0, actual_time - free_flow_time)
            total_delay = delay_per_vehicle * vehicle_count / 3600  # vehicle-hours
            tti = TrafficFlowTheory.calculate_travel_time_index(actual_time, free_flow_time)
            
            # Safety metrics
            speed_variance = speed_std ** 2
            cv = speed_std / avg_speed if avg_speed > 0 else 0.0
            speed_differential = speed_85th - speed_15th
            
            # Environmental metrics (simplified models)
            fuel_consumption_rate = self._calculate_fuel_consumption(avg_speed, speed_std)
            emissions_factor = self._calculate_emissions_factor(avg_speed, density)
            
            # Geometric factors
            road_width = 3.5 * lane_count  # meters (standard lane width)
            grade = 0.0  # Would need elevation data
            
            return RoadMetrics(
                road_name=road_name,
                road_length=road_length,
                vehicle_count=vehicle_count,
                total_vehicles_passed=vehicle_count,  # Simplified
                avg_speed=avg_speed,
                median_speed=median_speed,
                speed_std=speed_std,
                speed_85th_percentile=speed_85th,
                speed_15th_percentile=speed_15th,
                speed_range=speed_range,
                flow_rate=flow_rate,
                density=density,
                occupancy=occupancy,
                capacity=capacity,
                vc_ratio=vc_ratio,
                level_of_service=los,
                delay_per_vehicle=delay_per_vehicle,
                total_delay=total_delay,
                travel_time_index=tti,
                speed_variance=speed_variance,
                coefficient_of_variation=cv,
                speed_differential=speed_differential,
                fuel_consumption_rate=fuel_consumption_rate,
                emissions_factor=emissions_factor,
                lane_count=lane_count,
                road_width=road_width,
                grade=grade,
                analysis_period=self.analysis_period,
                peak_hour_factor=1.0  # Simplified
            )
            
        except Exception as e:
            self.logProxy.logger.error(f"Failed to analyze road {road_name}: {e}")
            return None
    
    def _get_vehicles_on_road(self, road, traffic) -> List[Dict]:
        """Get vehicles currently on a specific road"""
        try:
            vehicles = []
            road_name = getattr(road, 'Name', 'Unknown')
            self.logProxy.logger.info(f"Road {road_name}: Attempting to get vehicles on road")

            # Try different methods to get vehicles on road
            road_vehicles = None
            count = 0

            # Method 1: Try GetTransientVehiclesOnRoad (if available)
            try:
                road_vehicles = traffic.GetTransientVehiclesOnRoad(road)
                count = getattr(road_vehicles, 'Count', 0)
                self.logProxy.logger.info(f"Road {road_name}: Using GetTransientVehiclesOnRoad, found {count} vehicles")
            except Exception as e1:
                self.logProxy.logger.warning(f"Road {road_name}: GetTransientVehiclesOnRoad failed: {e1}")

                    # Method 2: Try alternative approach - sample road positions
                try:
                    # Sample multiple positions along the road using GetPositionAt
                    road_positions = []
                    vehicles_collected = []

                    if hasattr(road, 'GetPositionAt') and hasattr(road, 'Length'):
                        road_length = road.Length
                        if road_length > 0:
                            # Sample positions based on mode and road length
                            if self.fast_mode:
                                # Fast mode: Use only 2-3 points for speed
                                sample_points = [0.0, 0.5, 1.0]  # Always 3 points in fast mode
                            else:
                                # Normal mode: Use fewer points for shorter roads, more for longer roads
                                if road_length < 200:
                                    sample_points = [0.0, 0.5, 1.0]  # 3 points for short roads
                                elif road_length < 500:
                                    sample_points = [0.0, 0.33, 0.67, 1.0]  # 4 points for medium roads
                                else:
                                    sample_points = [0.0, 0.25, 0.5, 0.75, 1.0]  # 5 points for long roads

                            for percent in sample_points:
                                try:
                                    # Get position at this percentage along the road
                                    position = road.GetPositionAt(percent)
                                    road_positions.append(position)

                                    # Search for vehicles near this position
                                    search_radius = min(100, max(30, road_length / 10))  # Smaller radius for road segments
                                    segment_vehicles = traffic.GetTransientVehiclesArround(search_radius, position)
                                    segment_count = getattr(segment_vehicles, 'Count', 0)

                                    self.logProxy.logger.info(f"Road {road_name}: Position {percent*100:.0f}% - found {segment_count} vehicles in {search_radius}m radius")

                                    # Collect vehicles from this segment (fewer in fast mode)
                                    max_per_segment = 5 if self.fast_mode else 10
                                    total_limit = 25 if self.fast_mode else 50

                                    for i in range(min(segment_count, max_per_segment)):
                                        try:
                                            v = segment_vehicles.Items(i)
                                            if v:
                                                speed = v.Speed(self.winRoadProxy.const._KiloMeterPerHour)
                                                pos = v.Position
                                                if speed > 0:
                                                    vehicles_collected.append({
                                                        'speed': speed,
                                                        'position': (pos.X, pos.Y, pos.Z),
                                                        'id': getattr(v, 'ID', f"{percent}_{i}"),
                                                        'segment': percent
                                                    })

                                            # Early exit if we have enough vehicles for this road
                                            if len(vehicles_collected) >= total_limit:
                                                break
                                        except Exception:
                                            continue

                                        # Early exit if we have enough vehicles for this road
                                        if len(vehicles_collected) >= total_limit:
                                            break

                                except Exception as pos_e:
                                    self.logProxy.logger.warning(f"Road {road_name}: Failed to get position at {percent*100:.0f}%: {pos_e}")

                            # Create a synthetic vehicle collection
                            if vehicles_collected:
                                self.logProxy.logger.info(f"Road {road_name}: Collected {len(vehicles_collected)} vehicles from {len(road_positions)} road segments")
                                # Return the collected vehicles directly instead of using road_vehicles
                                return vehicles_collected
                            else:
                                self.logProxy.logger.warning(f"Road {road_name}: No vehicles found near any road segment")
                                return []
                        else:
                            self.logProxy.logger.warning(f"Road {road_name}: Invalid road length: {road_length}")
                            return []
                    else:
                        self.logProxy.logger.warning(f"Road {road_name}: Missing GetPositionAt method or Length attribute")
                        return []
                except Exception as e2:
                    self.logProxy.logger.error(f"Road {road_name}: Area search failed: {e2}")
                    return []

            # Process the vehicles we found
            # Handle both COM object and list returns
            if isinstance(road_vehicles, list):
                # Direct list of vehicle dictionaries (from new approach)
                vehicles = road_vehicles
                self.logProxy.logger.info(f"Road {road_name}: Using pre-collected vehicle list with {len(vehicles)} vehicles")
            else:
                # COM object (original approach)
                vehicles = []
                for i in range(min(count, 100)):  # Limit to 100 vehicles for performance
                    try:
                        v = road_vehicles.Items(i)
                        if v:
                            try:
                                speed = v.Speed(self.winRoadProxy.const._KiloMeterPerHour)
                                pos = v.Position

                                # Only include vehicles with valid speeds
                                if speed > 0:
                                    vehicles.append({
                                        'speed': speed,
                                        'position': (pos.X, pos.Y, pos.Z),
                                        'id': getattr(v, 'ID', i)
                                    })
                            except Exception as speed_e:
                                self.logProxy.logger.warning(f"Road {road_name}: Error getting speed for vehicle {i}: {speed_e}")
                        else:
                            self.logProxy.logger.warning(f"Road {road_name}: Vehicle {i} is null")
                    except Exception as veh_e:
                        self.logProxy.logger.warning(f"Road {road_name}: Error processing vehicle {i}: {veh_e}")

            self.logProxy.logger.info(f"Road {road_name}: Retrieved {len(vehicles)} valid vehicles")
            return vehicles
        except Exception as e:
            self.logProxy.logger.error(f"Failed to get vehicles on road: {e}")
            return []

    def _analyze_general_area(self, traffic, center, vehicle_count) -> Optional[RoadMetrics]:
        """Analyze vehicles in a general area when road-specific analysis fails"""
        try:
            self.logProxy.logger.info(f"Performing general area analysis as fallback with {vehicle_count} vehicles")

            # Use the existing vehicle data to avoid another expensive API call
            vehicles = traffic.GetTransientVehiclesArround(800, center)  # Slightly smaller radius for better performance
            count = getattr(vehicles, 'Count', 0)

            self.logProxy.logger.info(f"General area: Processing {count} vehicles from API")

            if count == 0:
                self.logProxy.logger.warning("General area: No vehicles returned from API")
                return None

            # Sample vehicles for analysis (limit for performance)
            # Use a more aggressive sampling to improve speed
            max_samples = min(150, count)  # Reduced from 200 to 150 for speed
            step = max(1, count // max_samples)
            speeds = []
            valid_vehicle_count = 0

            self.logProxy.logger.info(f"General area: Sampling {max_samples} vehicles with step {step}")

            # Add timeout mechanism
            import time
            start_time = time.time()
            max_processing_time = 10.0  # 10 seconds max

            for i in range(0, count, step):
                # Check timeout
                if time.time() - start_time > max_processing_time:
                    self.logProxy.logger.warning(f"General area: Processing timeout after {max_processing_time}s, collected {len(speeds)} samples")
                    break

                if len(speeds) >= max_samples:
                    break  # Stop once we have enough samples

                try:
                    v = vehicles.Items(i)
                    if v:
                        try:
                            speed = v.Speed(self.winRoadProxy.const._KiloMeterPerHour)
                            if speed > 0:  # Only include moving vehicles
                                speeds.append(speed)
                                valid_vehicle_count += 1
                        except Exception as speed_e:
                            # Skip vehicles with speed errors
                            continue
                except Exception as item_e:
                    # Skip problematic vehicle items
                    continue

                # Progress logging every 50 vehicles
                if i % 50 == 0 and i > 0:
                    elapsed = time.time() - start_time
                    self.logProxy.logger.info(f"General area: Processed {i}/{count} vehicles, {len(speeds)} valid samples in {elapsed:.1f}s")

            self.logProxy.logger.info(f"General area: Collected {len(speeds)} valid speed measurements from {valid_vehicle_count} vehicles")

            if len(speeds) < 5:  # Need minimum sample size
                self.logProxy.logger.warning(f"General area: Insufficient data - only {len(speeds)} valid measurements")
                return None

            # Calculate basic metrics efficiently
            self.logProxy.logger.info("General area: Calculating traffic metrics")
            avg_speed = statistics.mean(speeds)
            median_speed = statistics.median(speeds)
            speed_std = statistics.stdev(speeds) if len(speeds) > 1 else 0.0

            # Calculate percentiles more efficiently
            sorted_speeds = sorted(speeds)
            speed_85th = sorted_speeds[int(0.85 * len(speeds))]
            speed_15th = sorted_speeds[int(0.15 * len(speeds))]
            speed_range = sorted_speeds[-1] - sorted_speeds[0]

            self.logProxy.logger.info(f"General area: Speed stats - Avg: {avg_speed:.1f} km/h, Range: {speed_range:.1f} km/h")

            # Calculate flow metrics (estimated)
            flow_rate = len(speeds) * 3600 / self.analysis_period  # veh/h
            density = flow_rate / avg_speed if avg_speed > 0 else 0.0

            # Use area-based occupancy estimate
            area_size = 800  # meters radius (matches API call)
            occupancy = min(100.0, (len(speeds) * 15) / (3.14159 * area_size * area_size / 1000000))  # rough estimate

            # Estimate capacity and LOS (urban default)
            capacity = TrafficFlowTheory.calculate_capacity(4, "urban")  # Assume 4 lanes
            vc_ratio = flow_rate / capacity if capacity > 0 else 0.0
            los = TrafficFlowTheory.calculate_level_of_service(vc_ratio, avg_speed, "urban")

            # Calculate delay and travel time metrics
            free_flow_speed = 60.0
            estimated_road_length = 1000.0  # 1km area
            free_flow_time = estimated_road_length / (free_flow_speed / 3.6)
            actual_time = estimated_road_length / (avg_speed / 3.6) if avg_speed > 0 else free_flow_time
            delay_per_vehicle = max(0, actual_time - free_flow_time)
            total_delay = delay_per_vehicle * len(speeds) / 3600
            tti = TrafficFlowTheory.calculate_travel_time_index(actual_time, free_flow_time)

            # Safety metrics
            speed_variance = speed_std ** 2
            cv = speed_std / avg_speed if avg_speed > 0 else 0.0
            speed_differential = speed_85th - speed_15th

            # Environmental metrics
            fuel_consumption_rate = self._calculate_fuel_consumption(avg_speed, speed_std)
            emissions_factor = self._calculate_emissions_factor(avg_speed, density)

            self.logProxy.logger.info(f"General area: Analysis complete - LOS: {los.value}, Flow: {flow_rate:.0f} veh/h")

            return RoadMetrics(
                road_name="General Area",
                road_length=estimated_road_length,
                vehicle_count=len(speeds),
                total_vehicles_passed=len(speeds),
                avg_speed=avg_speed,
                median_speed=median_speed,
                speed_std=speed_std,
                speed_85th_percentile=speed_85th,
                speed_15th_percentile=speed_15th,
                speed_range=speed_range,
                flow_rate=flow_rate,
                density=density,
                occupancy=occupancy,
                capacity=capacity,
                vc_ratio=vc_ratio,
                level_of_service=los,
                delay_per_vehicle=delay_per_vehicle,
                total_delay=total_delay,
                travel_time_index=tti,
                speed_variance=speed_variance,
                coefficient_of_variation=cv,
                speed_differential=speed_differential,
                fuel_consumption_rate=fuel_consumption_rate,
                emissions_factor=emissions_factor,
                lane_count=4,  # Estimated
                road_width=14.0,  # 4 lanes * 3.5m
                grade=0.0,
                analysis_period=self.analysis_period,
                peak_hour_factor=1.0
            )

        except Exception as e:
            self.logProxy.logger.error(f"General area analysis failed: {e}")
            return None

    def _calculate_network_metrics(self, road_metrics: Dict[str, RoadMetrics], 
                                 total_vehicles: int, total_vehicle_miles: float) -> NetworkMetrics:
        """Calculate network-wide performance metrics"""
        if not road_metrics:
            return NetworkMetrics(0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0.0, 0.0)
        
        # Network averages
        network_avg_speed = statistics.mean([m.avg_speed for m in road_metrics.values()])
        network_delay = sum(m.total_delay for m in road_metrics.values())
        network_efficiency = sum(m.flow_rate * m.avg_speed for m in road_metrics.values())
        
        # Congestion distribution
        congested_roads = sum(1 for m in road_metrics.values() if m.level_of_service in [LevelOfService.E, LevelOfService.F])
        free_flow_roads = sum(1 for m in road_metrics.values() if m.level_of_service in [LevelOfService.A, LevelOfService.B])
        
        # Safety indicators
        speed_violation_rate = sum(1 for m in road_metrics.values() if m.speed_85th_percentile > 80) / len(road_metrics)
        aggressive_driving_rate = sum(1 for m in road_metrics.values() if m.coefficient_of_variation > 0.3) / len(road_metrics)
        
        return NetworkMetrics(
            total_roads=len(road_metrics),
            total_vehicles=total_vehicles,
            total_vehicle_miles=total_vehicle_miles,
            network_avg_speed=network_avg_speed,
            network_delay=network_delay,
            network_efficiency=network_efficiency,
            congested_roads=congested_roads,
            free_flow_roads=free_flow_roads,
            speed_violation_rate=speed_violation_rate,
            aggressive_driving_rate=aggressive_driving_rate
        )
    
    def _calculate_fuel_consumption(self, avg_speed: float, speed_std: float) -> float:
        """Calculate fuel consumption rate (L/100km equivalent)"""
        # Simplified fuel consumption model based on speed and variability
        base_consumption = 8.0  # L/100km at optimal speed
        speed_factor = 1.0 + abs(avg_speed - 60) / 100  # Penalty for non-optimal speed
        variability_factor = 1.0 + speed_std / 50  # Penalty for speed variability
        return base_consumption * speed_factor * variability_factor
    
    def _calculate_emissions_factor(self, avg_speed: float, density: float) -> float:
        """Calculate emissions factor (CO2 equivalent)"""
        # Simplified emissions model
        base_emissions = 200  # g CO2/km
        speed_factor = 1.0 + (60 - avg_speed) / 200  # Higher emissions at lower speeds
        density_factor = 1.0 + density / 100  # Higher emissions in dense traffic
        return base_emissions * speed_factor * density_factor

class TrafficReportGenerator:
    """Generate comprehensive traffic analysis reports"""
    
    @staticmethod
    def generate_road_report(metrics: RoadMetrics) -> str:
        """Generate detailed report for a single road"""
        report = f"""
=== TRAFFIC ANALYSIS REPORT: {metrics.road_name} ===

BASIC METRICS:
• Vehicle Count: {metrics.vehicle_count} vehicles
• Road Length: {metrics.road_length:.1f} m
• Lane Count: {metrics.lane_count} lanes
• Analysis Period: {metrics.analysis_period:.1f} seconds

SPEED ANALYSIS:
• Average Speed: {metrics.avg_speed:.1f} km/h
• Median Speed: {metrics.median_speed:.1f} km/h
• 85th Percentile: {metrics.speed_85th_percentile:.1f} km/h
• 15th Percentile: {metrics.speed_15th_percentile:.1f} km/h
• Speed Range: {metrics.speed_range:.1f} km/h
• Speed Std Dev: {metrics.speed_std:.1f} km/h
• Coefficient of Variation: {metrics.coefficient_of_variation:.3f}

TRAFFIC FLOW:
• Flow Rate: {metrics.flow_rate:.1f} veh/h
• Density: {metrics.density:.1f} veh/km
• Occupancy: {metrics.occupancy:.1f}%
• Capacity: {metrics.capacity:.0f} veh/h
• Volume/Capacity Ratio: {metrics.vc_ratio:.3f}
• Level of Service: {metrics.level_of_service.value}

PERFORMANCE:
• Delay per Vehicle: {metrics.delay_per_vehicle:.1f} seconds
• Total Delay: {metrics.total_delay:.2f} vehicle-hours
• Travel Time Index: {metrics.travel_time_index:.2f}

SAFETY INDICATORS:
• Speed Variance: {metrics.speed_variance:.1f}
• Speed Differential: {metrics.speed_differential:.1f} km/h

ENVIRONMENTAL:
• Fuel Consumption: {metrics.fuel_consumption_rate:.1f} L/100km
• Emissions Factor: {metrics.emissions_factor:.0f} g CO2/km
"""
        return report
    
    @staticmethod
    def generate_network_summary(road_metrics: Dict[str, RoadMetrics], 
                               network_metrics: NetworkMetrics) -> str:
        """Generate network-wide summary report"""
        report = f"""
=== NETWORK TRAFFIC ANALYSIS SUMMARY ===

NETWORK OVERVIEW:
• Total Roads Analyzed: {network_metrics.total_roads}
• Total Vehicles: {network_metrics.total_vehicles}
• Total Vehicle-Miles: {network_metrics.total_vehicle_miles:.1f}

PERFORMANCE METRICS:
• Network Average Speed: {network_metrics.network_avg_speed:.1f} km/h
• Total Network Delay: {network_metrics.network_delay:.2f} vehicle-hours
• Network Efficiency: {network_metrics.network_efficiency:.0f}

CONGESTION DISTRIBUTION:
• Free Flow Roads (LOS A-B): {network_metrics.free_flow_roads}
• Congested Roads (LOS E-F): {network_metrics.congested_roads}
• Congestion Rate: {(network_metrics.congested_roads/network_metrics.total_roads*100):.1f}%

SAFETY INDICATORS:
• Speed Violation Rate: {network_metrics.speed_violation_rate*100:.1f}%
• Aggressive Driving Rate: {network_metrics.aggressive_driving_rate*100:.1f}%

TOP PERFORMING ROADS:
"""
        
        # Sort roads by performance (low delay, high speed)
        sorted_roads = sorted(road_metrics.items(), 
                            key=lambda x: (x[1].delay_per_vehicle, -x[1].avg_speed))
        
        for i, (name, metrics) in enumerate(sorted_roads[:5]):
            report += f"• {i+1}. {name}: {metrics.avg_speed:.1f} km/h, LOS {metrics.level_of_service.value}\n"
        
        report += "\nMOST CONGESTED ROADS:\n"
        congested_roads = [(name, metrics) for name, metrics in road_metrics.items() 
                          if metrics.level_of_service in [LevelOfService.E, LevelOfService.F]]
        congested_roads.sort(key=lambda x: x[1].delay_per_vehicle, reverse=True)
        
        for i, (name, metrics) in enumerate(congested_roads[:5]):
            report += f"• {i+1}. {name}: {metrics.delay_per_vehicle:.1f}s delay, LOS {metrics.level_of_service.value}\n"
        
        return report
