import 'package:flutter/material.dart'; enum FieldTestEventType { rideStarted, rideStopped, gpsStale, gpsRecovered, gpsJumpRejected, gpsAccuracyDegraded, imuSaturation, imuRecovered, telemetryGap, telemetryRecovered, timestampError, sampleAccepted, sampleSuspect, sampleRejected, accelerationEvent, brakingEvent, performanceRunStarted, performanceRunCompleted, performanceRunRejected, appPaused, appResumed, foregroundServiceStarted, foregroundServiceStopped, databaseFlush, databaseQueueWarning, databaseQueueOverflow, databaseRecovery, exportStarted, exportCompleted, exportFailed, sensorInitialized, sensorError, gpsInitialized, gpsError, calibrationStarted, calibrationCompleted, roadAlertReceived, ttsAnnounced, audioFailure, networkError; String get displayName { switch (this) { case FieldTestEventType.rideStarted: return 'RIDE_STARTED'; case FieldTestEventType.rideStopped: return 'RIDE_STOPPED'; case FieldTestEventType.gpsStale: return 'GPS_STALE'; case FieldTestEventType.gpsRecovered: return 'GPS_RECOVERED'; case FieldTestEventType.gpsJumpRejected: return 'GPS_JUMP_REJECTED'; case FieldTestEventType.gpsAccuracyDegraded: return 'GPS_ACCURACY_DEGRADED'; case FieldTestEventType.imuSaturation: return 'IMU_SATURATION'; case FieldTestEventType.imuRecovered: return 'IMU_RECOVERED'; case FieldTestEventType.telemetryGap: return 'TELEMETRY_GAP'; case FieldTestEventType.telemetryRecovered: return 'TELEMETRY_RECOVERED'; case FieldTestEventType.timestampError: return 'TIMESTAMP_ERROR'; case FieldTestEventType.sampleAccepted: return 'SAMPLE_ACCEPTED'; case FieldTestEventType.sampleSuspect: return 'SAMPLE_SUSPECT'; case FieldTestEventType.sampleRejected: return 'SAMPLE_REJECTED'; case FieldTestEventType.accelerationEvent: return 'ACCELERATION_EVENT'; case FieldTestEventType.brakingEvent: return 'BRAKING_EVENT'; case FieldTestEventType.performanceRunStarted: return 'PERFORMANCE_RUN_STARTED'; case FieldTestEventType.performanceRunCompleted: return 'PERFORMANCE_RUN_COMPLETED'; case FieldTestEventType.performanceRunRejected: return 'PERFORMANCE_RUN_REJECTED'; case FieldTestEventType.appPaused: return 'APP_PAUSED'; case FieldTestEventType.appResumed: return 'APP_RESUMED'; case FieldTestEventType.foregroundServiceStarted: return 'FOREGROUND_SERVICE_STARTED'; case FieldTestEventType.foregroundServiceStopped: return 'FOREGROUND_SERVICE_STOPPED'; case FieldTestEventType.databaseFlush: return 'DATABASE_FLUSH'; case FieldTestEventType.databaseQueueWarning: return 'DATABASE_QUEUE_WARNING'; case FieldTestEventType.databaseQueueOverflow: return 'DATABASE_QUEUE_OVERFLOW'; case FieldTestEventType.databaseRecovery: return 'DATABASE_RECOVERY'; case FieldTestEventType.exportStarted: return 'EXPORT_STARTED'; case FieldTestEventType.exportCompleted: return 'EXPORT_COMPLETED'; case FieldTestEventType.exportFailed: return 'EXPORT_FAILED'; case FieldTestEventType.sensorInitialized: return 'SENSOR_INITIALIZED'; case FieldTestEventType.sensorError: return 'SENSOR_ERROR'; case FieldTestEventType.gpsInitialized: return 'GPS_INITIALIZED'; case FieldTestEventType.gpsError: return 'GPS_ERROR'; case FieldTestEventType.calibrationStarted: return 'CALIBRATION_STARTED'; case FieldTestEventType.calibrationCompleted: return 'CALIBRATION_COMPLETED'; case FieldTestEventType.roadAlertReceived: return 'ROAD_ALERT_RECEIVED'; case FieldTestEventType.ttsAnnounced: return 'TTS_ANNOUNCED'; case FieldTestEventType.audioFailure: return 'AUDIO_FAILURE'; case FieldTestEventType.networkError: return 'NETWORK_ERROR'; } } static FieldTestEventType fromString(String val) { final clean = val.toUpperCase().replaceAll('-', '_'); for (final e in FieldTestEventType.values) { if (e.displayName == clean || e.name.toUpperCase() == clean) { return e; } } return FieldTestEventType.sampleAccepted; } } enum EventSeverity { info, warning, error, critical; String get displayName => name.toUpperCase(); Color get color { switch (this) { case EventSeverity.info: return Colors.cyanAccent; case EventSeverity.warning: return Colors.amberAccent; case EventSeverity.error: return Colors.orangeAccent; case EventSeverity.critical: return Colors.redAccent; } } static EventSeverity fromString(String val) { final clean = val.toLowerCase(); for (final s in EventSeverity.values) { if (s.name.toLowerCase() == clean) { return s; } } return EventSeverity.info; } } class FieldTestEvent { final int? id; final DateTime timestamp; final FieldTestEventType eventType; final int? rideId; final EventSeverity severity; final String message; final DateTime? telemetryTimestamp; final int? gpsAgeMs; final double? speed; final double? latitude; final double? longitude; final double? gpsAccuracy; final double? leanAngle; final double? longitudinalG; final double? lateralG; final double? overallConfidence; final Map? metadata; const FieldTestEvent({ this.id, required this.timestamp, required this.eventType, this.rideId, required this.severity, required this.message, this.telemetryTimestamp, this.gpsAgeMs, this.speed, this.latitude, this.longitude, this.gpsAccuracy, this.leanAngle, this.longitudinalG, this.lateralG, this.overallConfidence, this.metadata, }); Map toJson() { return { 'id': id, 'timestamp': timestamp.toIso8601String(), 'eventType': eventType.displayName, 'rideId': rideId, 'severity': severity.displayName, 'message': message, 'telemetryTimestamp': telemetryTimestamp?.toIso8601String(), 'gpsAgeMs': gpsAgeMs, 'speed': speed, 'latitude': latitude, 'longitude': longitude, 'gpsAccuracy': gpsAccuracy, 'leanAngle': leanAngle, 'longitudinalG': longitudinalG, 'lateralG': lateralG, 'overallConfidence': overallConfidence, 'metadata': metadata, }; } factory FieldTestEvent.fromJson(Map json) { return FieldTestEvent( id: json['id'] as int?, timestamp: DateTime.parse(json['timestamp'] as String), eventType: FieldTestEventType.fromString(json['eventType'] as String), rideId: json['rideId'] as int?, severity: EventSeverity.fromString(json['severity'] as String), message: json['message'] as String? ?? '', telemetryTimestamp: json['telemetryTimestamp'] != null ? DateTime.parse(json['telemetryTimestamp'] as String) : null, gpsAgeMs: json['gpsAgeMs'] as int?, speed: (json['speed'] as num?)?.toDouble(), latitude: (json['latitude'] as num?)?.toDouble(), longitude: (json['longitude'] as num?)?.toDouble(), gpsAccuracy: (json['gpsAccuracy'] as num?)?.toDouble(), leanAngle: (json['leanAngle'] as num?)?.toDouble(), longitudinalG: (json['longitudinalG'] as num?)?.toDouble(), lateralG: (json['lateralG'] as num?)?.toDouble(), overallConfidence: (json['overallConfidence'] as num?)?.toDouble(), metadata: json['metadata'] as Map?, ); } }