class FieldTestSummary { final int? id; final int rideId; final DateTime startTime; final DateTime? endTime; final Duration duration; final int totalSamples; final int validSamples; final int suspectSamples; final int rejectedSamples; final double validPercentage; final double suspectPercentage; final double rejectedPercentage; final int gpsFixCount; final int gpsStaleEventCount; final int gpsJumpRejectCount; final int? maxGpsAgeMs; final double? averageGpsAccuracy; final double? worstGpsAccuracy; final int telemetryGapCount; final int? maxTelemetryGapMs; final int imuSaturationCount; final double? maxSpeedMph; final double? maxLeanAngle; final double? maxLongitudinalG; final double? maxLateralG; final int accelerationEventCount; final int brakingEventCount; final int zeroTo60Count; final int zeroTo100Count; final double? bestZeroTo60; final double? bestZeroTo100; final int databaseSamplesWritten; final int databaseSamplesLost; final int eventCount; final double? overallConfidence; final int rideQualityScore; final String rideQualityRating; final bool wasRecoveredAfterCrash; final bool wasInterrupted; final String? exportIntegrity; const FieldTestSummary({ this.id, required this.rideId, required this.startTime, this.endTime, required this.duration, required this.totalSamples, required this.validSamples, required this.suspectSamples, required this.rejectedSamples, required this.validPercentage, required this.suspectPercentage, required this.rejectedPercentage, required this.gpsFixCount, required this.gpsStaleEventCount, required this.gpsJumpRejectCount, this.maxGpsAgeMs, this.averageGpsAccuracy, this.worstGpsAccuracy, required this.telemetryGapCount, this.maxTelemetryGapMs, required this.imuSaturationCount, this.maxSpeedMph, this.maxLeanAngle, this.maxLongitudinalG, this.maxLateralG, required this.accelerationEventCount, required this.brakingEventCount, required this.zeroTo60Count, required this.zeroTo100Count, this.bestZeroTo60, this.bestZeroTo100, required this.databaseSamplesWritten, required this.databaseSamplesLost, required this.eventCount, this.overallConfidence, required this.rideQualityScore, required this.rideQualityRating, this.wasRecoveredAfterCrash = false, this.wasInterrupted = false, this.exportIntegrity, }); Map toJson() { return { 'id': id, 'rideId': rideId, 'startTime': startTime.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'durationSeconds': duration.inSeconds, 'totalSamples': totalSamples, 'validSamples': validSamples, 'suspectSamples': suspectSamples, 'rejectedSamples': rejectedSamples, 'validPercentage': validPercentage, 'suspectPercentage': suspectPercentage, 'rejectedPercentage': rejectedPercentage, 'gpsFixCount': gpsFixCount, 'gpsStaleEventCount': gpsStaleEventCount, 'gpsJumpRejectCount': gpsJumpRejectCount, 'maxGpsAgeMs': maxGpsAgeMs, 'averageGpsAccuracy': averageGpsAccuracy, 'worstGpsAccuracy': worstGpsAccuracy, 'telemetryGapCount': telemetryGapCount, 'maxTelemetryGapMs': maxTelemetryGapMs, 'imuSaturationCount': imuSaturationCount, 'maxSpeedMph': maxSpeedMph, 'maxLeanAngle': maxLeanAngle, 'maxLongitudinalG': maxLongitudinalG, 'maxLateralG': maxLateralG, 'accelerationEventCount': accelerationEventCount, 'brakingEventCount': brakingEventCount, 'zeroTo60Count': zeroTo60Count, 'zeroTo100Count': zeroTo100Count, 'bestZeroTo60': bestZeroTo60, 'bestZeroTo100': bestZeroTo100, 'databaseSamplesWritten': databaseSamplesWritten, 'databaseSamplesLost': databaseSamplesLost, 'eventCount': eventCount, 'overallConfidence': overallConfidence, 'rideQualityScore': rideQualityScore, 'rideQualityRating': rideQualityRating, 'wasRecoveredAfterCrash': wasRecoveredAfterCrash, 'wasInterrupted': wasInterrupted, 'exportIntegrity': exportIntegrity, }; } factory FieldTestSummary.fromJson(Map json) { return FieldTestSummary( id: json['id'] as int?, rideId: json['rideId'] as int, startTime: DateTime.parse(json['startTime'] as String), endTime: json['endTime'] != null ? DateTime.parse(json['endTime'] as String) : null, duration: Duration(seconds: json['durationSeconds'] as int? ?? 0), totalSamples: json['totalSamples'] as int? ?? 0, validSamples: json['validSamples'] as int? ?? 0, suspectSamples: json['suspectSamples'] as int? ?? 0, rejectedSamples: json['rejectedSamples'] as int? ?? 0, validPercentage: (json['validPercentage'] as num?)?.toDouble() ?? 0.0, suspectPercentage: (json['suspectPercentage'] as num?)?.toDouble() ?? 0.0, rejectedPercentage: (json['rejectedPercentage'] as num?)?.toDouble() ?? 0.0, gpsFixCount: json['gpsFixCount'] as int? ?? 0, gpsStaleEventCount: json['gpsStaleEventCount'] as int? ?? 0, gpsJumpRejectCount: json['gpsJumpRejectCount'] as int? ?? 0, maxGpsAgeMs: json['maxGpsAgeMs'] as int?, averageGpsAccuracy: (json['averageGpsAccuracy'] as num?)?.toDouble(), worstGpsAccuracy: (json['worstGpsAccuracy'] as num?)?.toDouble(), telemetryGapCount: json['telemetryGapCount'] as int? ?? 0, maxTelemetryGapMs: json['maxTelemetryGapMs'] as int?, imuSaturationCount: json['imuSaturationCount'] as int? ?? 0, maxSpeedMph: (json['maxSpeedMph'] as num?)?.toDouble(), maxLeanAngle: (json['maxLeanAngle'] as num?)?.toDouble(), maxLongitudinalG: (json['maxLongitudinalG'] as num?)?.toDouble(), maxLateralG: (json['maxLateralG'] as num?)?.toDouble(), accelerationEventCount: json['accelerationEventCount'] as int? ?? 0, brakingEventCount: json['brakingEventCount'] as int? ?? 0, zeroTo60Count: json['zeroTo60Count'] as int? ?? 0, zeroTo100Count: json['zeroTo100Count'] as int? ?? 0, bestZeroTo60: (json['bestZeroTo60'] as num?)?.toDouble(), bestZeroTo100: (json['bestZeroTo100'] as num?)?.toDouble(), databaseSamplesWritten: json['databaseSamplesWritten'] as int? ?? 0, databaseSamplesLost: json['databaseSamplesLost'] as int? ?? 0, eventCount: json['eventCount'] as int? ?? 0, overallConfidence: (json['overallConfidence'] as num?)?.toDouble(), rideQualityScore: json['rideQualityScore'] as int? ?? 0, rideQualityRating: json['rideQualityRating'] as String? ?? 'INVALID', wasRecoveredAfterCrash: json['wasRecoveredAfterCrash'] as bool? ?? false, wasInterrupted: json['wasInterrupted'] as bool? ?? false, exportIntegrity: json['exportIntegrity'] as String?, ); } }