""" Analytics & Predictive Insights serializers for Enterprise Incident Management API Provides comprehensive serialization for KPIs, metrics, predictive models, and insights """ from rest_framework import serializers from django.contrib.auth import get_user_model from ..models import ( KPIMetric, KPIMeasurement, IncidentRecurrenceAnalysis, PredictiveModel, AnomalyDetection, CostImpactAnalysis, DashboardConfiguration, HeatmapData, PredictiveInsight ) User = get_user_model() class KPIMetricSerializer(serializers.ModelSerializer): """Serializer for KPI metrics""" created_by_username = serializers.CharField(source='created_by.username', read_only=True) measurement_count = serializers.SerializerMethodField() latest_measurement = serializers.SerializerMethodField() class Meta: model = KPIMetric fields = [ 'id', 'name', 'description', 'metric_type', 'aggregation_type', 'incident_categories', 'incident_severities', 'incident_priorities', 'calculation_formula', 'time_window_hours', 'is_active', 'is_system_metric', 'created_by_username', 'created_at', 'updated_at', 'measurement_count', 'latest_measurement' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_measurement_count(self, obj): """Get the number of measurements for this metric""" return obj.measurements.count() def get_latest_measurement(self, obj): """Get the latest measurement for this metric""" latest = obj.measurements.first() if latest: return { 'value': str(latest.value), 'unit': latest.unit, 'calculated_at': latest.calculated_at, 'incident_count': latest.incident_count } return None class KPIMeasurementSerializer(serializers.ModelSerializer): """Serializer for KPI measurements""" metric_name = serializers.CharField(source='metric.name', read_only=True) metric_type = serializers.CharField(source='metric.metric_type', read_only=True) class Meta: model = KPIMeasurement fields = [ 'id', 'metric', 'metric_name', 'metric_type', 'value', 'unit', 'measurement_period_start', 'measurement_period_end', 'incident_count', 'sample_size', 'metadata', 'calculated_at' ] read_only_fields = ['id', 'calculated_at'] class IncidentRecurrenceAnalysisSerializer(serializers.ModelSerializer): """Serializer for incident recurrence analysis""" primary_incident_title = serializers.CharField(source='primary_incident.title', read_only=True) primary_incident_severity = serializers.CharField(source='primary_incident.severity', read_only=True) recurring_incident_count = serializers.SerializerMethodField() recurring_incident_titles = serializers.SerializerMethodField() class Meta: model = IncidentRecurrenceAnalysis fields = [ 'id', 'primary_incident', 'primary_incident_title', 'primary_incident_severity', 'recurring_incidents', 'recurring_incident_count', 'recurring_incident_titles', 'recurrence_type', 'confidence_score', 'recurrence_rate', 'common_keywords', 'common_categories', 'time_pattern', 'total_affected_users', 'total_downtime_hours', 'estimated_cost_impact', 'prevention_recommendations', 'automation_opportunities', 'is_resolved', 'resolution_actions', 'created_at', 'updated_at', 'model_version' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_recurring_incident_count(self, obj): """Get the number of recurring incidents""" return obj.recurring_incidents.count() def get_recurring_incident_titles(self, obj): """Get titles of recurring incidents""" return [incident.title for incident in obj.recurring_incidents.all()] class PredictiveModelSerializer(serializers.ModelSerializer): """Serializer for predictive models""" created_by_username = serializers.CharField(source='created_by.username', read_only=True) insight_count = serializers.SerializerMethodField() anomaly_detection_count = serializers.SerializerMethodField() performance_summary = serializers.SerializerMethodField() class Meta: model = PredictiveModel fields = [ 'id', 'name', 'description', 'model_type', 'algorithm_type', 'model_config', 'feature_columns', 'target_column', 'training_data_period_days', 'min_training_samples', 'accuracy_score', 'precision_score', 'recall_score', 'f1_score', 'status', 'version', 'model_file_path', 'last_trained_at', 'training_duration_seconds', 'training_samples_count', 'auto_retrain_enabled', 'retrain_frequency_days', 'performance_threshold', 'created_by_username', 'created_at', 'updated_at', 'insight_count', 'anomaly_detection_count', 'performance_summary' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_insight_count(self, obj): """Get the number of insights generated by this model""" return obj.insights.count() def get_anomaly_detection_count(self, obj): """Get the number of anomaly detections by this model""" return obj.anomaly_detections.count() def get_performance_summary(self, obj): """Get a summary of model performance metrics""" return { 'accuracy': obj.accuracy_score, 'precision': obj.precision_score, 'recall': obj.recall_score, 'f1_score': obj.f1_score, 'overall_health': self._calculate_overall_health(obj) } def _calculate_overall_health(self, obj): """Calculate overall model health score""" if not all([obj.accuracy_score, obj.precision_score, obj.recall_score, obj.f1_score]): return 'Unknown' avg_score = (obj.accuracy_score + obj.precision_score + obj.recall_score + obj.f1_score) / 4 if avg_score >= 0.9: return 'Excellent' elif avg_score >= 0.8: return 'Good' elif avg_score >= 0.7: return 'Fair' else: return 'Poor' class AnomalyDetectionSerializer(serializers.ModelSerializer): """Serializer for anomaly detection results""" model_name = serializers.CharField(source='model.name', read_only=True) model_type = serializers.CharField(source='model.model_type', read_only=True) resolved_by_username = serializers.CharField(source='resolved_by.username', read_only=True) related_incident_count = serializers.SerializerMethodField() related_incident_titles = serializers.SerializerMethodField() time_since_detection = serializers.SerializerMethodField() class Meta: model = AnomalyDetection fields = [ 'id', 'model', 'model_name', 'model_type', 'anomaly_type', 'severity', 'status', 'confidence_score', 'anomaly_score', 'threshold_used', 'detected_at', 'time_window_start', 'time_window_end', 'related_incidents', 'related_incident_count', 'related_incident_titles', 'affected_services', 'affected_metrics', 'description', 'root_cause_analysis', 'impact_assessment', 'actions_taken', 'resolved_at', 'resolved_by', 'resolved_by_username', 'metadata', 'time_since_detection' ] read_only_fields = ['id', 'detected_at'] def get_related_incident_count(self, obj): """Get the number of related incidents""" return obj.related_incidents.count() def get_related_incident_titles(self, obj): """Get titles of related incidents""" return [incident.title for incident in obj.related_incidents.all()] def get_time_since_detection(self, obj): """Get time elapsed since anomaly detection""" from django.utils import timezone return timezone.now() - obj.detected_at class CostImpactAnalysisSerializer(serializers.ModelSerializer): """Serializer for cost impact analysis""" incident_title = serializers.CharField(source='incident.title', read_only=True) incident_severity = serializers.CharField(source='incident.severity', read_only=True) validated_by_username = serializers.CharField(source='validated_by.username', read_only=True) cost_per_hour = serializers.SerializerMethodField() cost_per_user = serializers.SerializerMethodField() class Meta: model = CostImpactAnalysis fields = [ 'id', 'incident', 'incident_title', 'incident_severity', 'cost_type', 'cost_amount', 'currency', 'calculation_method', 'calculation_details', 'downtime_hours', 'affected_users', 'revenue_impact', 'business_unit', 'service_tier', 'is_validated', 'validated_by', 'validated_by_username', 'validated_at', 'validation_notes', 'created_at', 'updated_at', 'cost_per_hour', 'cost_per_user' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_cost_per_hour(self, obj): """Calculate cost per hour of downtime""" if obj.downtime_hours and obj.downtime_hours > 0: return float(obj.cost_amount / obj.downtime_hours) return None def get_cost_per_user(self, obj): """Calculate cost per affected user""" if obj.affected_users and obj.affected_users > 0: return float(obj.cost_amount / obj.affected_users) return None class DashboardConfigurationSerializer(serializers.ModelSerializer): """Serializer for dashboard configurations""" created_by_username = serializers.CharField(source='created_by.username', read_only=True) allowed_user_count = serializers.SerializerMethodField() allowed_usernames = serializers.SerializerMethodField() widget_count = serializers.SerializerMethodField() class Meta: model = DashboardConfiguration fields = [ 'id', 'name', 'description', 'dashboard_type', 'layout_config', 'widget_configs', 'widget_count', 'is_public', 'allowed_users', 'allowed_user_count', 'allowed_usernames', 'allowed_roles', 'auto_refresh_enabled', 'refresh_interval_seconds', 'is_active', 'created_by_username', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_allowed_user_count(self, obj): """Get the number of allowed users""" return obj.allowed_users.count() def get_allowed_usernames(self, obj): """Get usernames of allowed users""" return [user.username for user in obj.allowed_users.all()] def get_widget_count(self, obj): """Get the number of widgets in this dashboard""" return len(obj.widget_configs) if obj.widget_configs else 0 class HeatmapDataSerializer(serializers.ModelSerializer): """Serializer for heatmap data""" data_point_count = serializers.SerializerMethodField() time_span_hours = serializers.SerializerMethodField() class Meta: model = HeatmapData fields = [ 'id', 'name', 'heatmap_type', 'time_period_start', 'time_period_end', 'time_granularity', 'data_points', 'data_point_count', 'color_scheme', 'aggregation_method', 'time_span_hours', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_data_point_count(self, obj): """Get the number of data points""" return len(obj.data_points) if obj.data_points else 0 def get_time_span_hours(self, obj): """Get the time span in hours""" from django.utils import timezone delta = obj.time_period_end - obj.time_period_start return delta.total_seconds() / 3600 class PredictiveInsightSerializer(serializers.ModelSerializer): """Serializer for predictive insights""" model_name = serializers.CharField(source='model.name', read_only=True) model_type = serializers.CharField(source='model.model_type', read_only=True) acknowledged_by_username = serializers.CharField(source='acknowledged_by.username', read_only=True) related_incident_count = serializers.SerializerMethodField() related_incident_titles = serializers.SerializerMethodField() time_until_expiry = serializers.SerializerMethodField() is_expired = serializers.SerializerMethodField() class Meta: model = PredictiveInsight fields = [ 'id', 'model', 'model_name', 'model_type', 'insight_type', 'title', 'description', 'confidence_level', 'confidence_score', 'predicted_value', 'prediction_horizon', 'prediction_date', 'input_features', 'supporting_evidence', 'related_incidents', 'related_incident_count', 'related_incident_titles', 'affected_services', 'recommendations', 'risk_assessment', 'is_acknowledged', 'acknowledged_by', 'acknowledged_by_username', 'acknowledged_at', 'is_validated', 'actual_value', 'validation_accuracy', 'generated_at', 'expires_at', 'time_until_expiry', 'is_expired' ] read_only_fields = ['id', 'generated_at'] def get_related_incident_count(self, obj): """Get the number of related incidents""" return obj.related_incidents.count() def get_related_incident_titles(self, obj): """Get titles of related incidents""" return [incident.title for incident in obj.related_incidents.all()] def get_time_until_expiry(self, obj): """Get time until insight expires""" from django.utils import timezone return obj.expires_at - timezone.now() def get_is_expired(self, obj): """Check if insight has expired""" return obj.is_expired # Summary and aggregation serializers class KPISummarySerializer(serializers.Serializer): """Serializer for KPI summary data""" metric_type = serializers.CharField() metric_name = serializers.CharField() current_value = serializers.DecimalField(max_digits=15, decimal_places=4) unit = serializers.CharField() trend = serializers.CharField() # 'up', 'down', 'stable' trend_percentage = serializers.DecimalField(max_digits=5, decimal_places=2) period_start = serializers.DateTimeField() period_end = serializers.DateTimeField() incident_count = serializers.IntegerField() target_value = serializers.DecimalField(max_digits=15, decimal_places=4, allow_null=True) target_met = serializers.BooleanField() class AnomalySummarySerializer(serializers.Serializer): """Serializer for anomaly summary data""" total_anomalies = serializers.IntegerField() critical_anomalies = serializers.IntegerField() high_anomalies = serializers.IntegerField() medium_anomalies = serializers.IntegerField() low_anomalies = serializers.IntegerField() unresolved_anomalies = serializers.IntegerField() false_positive_rate = serializers.DecimalField(max_digits=5, decimal_places=2) average_resolution_time = serializers.DurationField() class CostSummarySerializer(serializers.Serializer): """Serializer for cost summary data""" total_cost = serializers.DecimalField(max_digits=15, decimal_places=2) currency = serializers.CharField() downtime_cost = serializers.DecimalField(max_digits=15, decimal_places=2) lost_revenue = serializers.DecimalField(max_digits=15, decimal_places=2) penalty_cost = serializers.DecimalField(max_digits=15, decimal_places=2) resource_cost = serializers.DecimalField(max_digits=15, decimal_places=2) total_downtime_hours = serializers.DecimalField(max_digits=10, decimal_places=2) total_affected_users = serializers.IntegerField() cost_per_hour = serializers.DecimalField(max_digits=10, decimal_places=2) cost_per_user = serializers.DecimalField(max_digits=10, decimal_places=2) class PredictiveInsightSummarySerializer(serializers.Serializer): """Serializer for predictive insight summary data""" total_insights = serializers.IntegerField() high_confidence_insights = serializers.IntegerField() medium_confidence_insights = serializers.IntegerField() low_confidence_insights = serializers.IntegerField() acknowledged_insights = serializers.IntegerField() validated_insights = serializers.IntegerField() expired_insights = serializers.IntegerField() average_accuracy = serializers.DecimalField(max_digits=5, decimal_places=2) active_models = serializers.IntegerField() class DashboardDataSerializer(serializers.Serializer): """Serializer for complete dashboard data""" kpi_summary = KPISummarySerializer(many=True) anomaly_summary = AnomalySummarySerializer() cost_summary = CostSummarySerializer() insight_summary = PredictiveInsightSummarySerializer() recent_anomalies = AnomalyDetectionSerializer(many=True) recent_insights = PredictiveInsightSerializer(many=True) heatmap_data = HeatmapDataSerializer(many=True) last_updated = serializers.DateTimeField()