calculateReputation method

Future<void> calculateReputation()

Implementation

Future<void> calculateReputation() async {
  final file = File(filePath);
  if (await file.exists()) {
    List<String> lines = await file.readAsLines();
    hasHistory = lines.isNotEmpty;

    // ⚠️ Additional validation: ignore if avgLatency of last entry is 0.0
    if (hasHistory) {
      final last = lines.last.split(',');
      final delivered = int.tryParse(last[6]) ?? 0;
      final latency = double.tryParse(last[7]) ?? 0.0;

      if (delivered == 0 || latency == 0.0) {
        hasHistory = false;
        if (kDebugMode) {
          print(
              "⚠️ Invalid history: average latency is zero or no packets were delivered. Ignored for reputation calculation.");
        }
      }
    }
  } else {
    hasHistory = false;
  }

  double normBattery = (battery / 100).clamp(0.0, 1.0);
  double normStorage = (storage / 100).clamp(0.0, 1.0);

  // Prevent reputation calculation if battery < 6% or storage ≤ 3%
  if (battery < 6 || storage <= 3) {
    if (kDebugMode) {
      print("Battery or storage too low to calculate reputation.");
    }
    reputation = 0.0;
    await _saveReputation();
    return;
  }

  // Derived metrics
  const double maxInteractionScorePossible = 50.0;

  double interactionScoreRaw =
      successfulInteractions * _recencyFactor() * diversity.toDouble();
  double interactionScore =
      (interactionScoreRaw / maxInteractionScorePossible).clamp(0.0, 1.0);

  double hist = totalInteractions > 0
      ? successfulInteractions / totalInteractions
      : 0.0;

  double latencyInSeconds = avgLatency / 1000;
  double qDelivery = deliveredPackets > 0
      ? (requestedPackets / deliveredPackets) * latencyInSeconds
      : 0.0;

  double repBattery = 0.0;
  double repStorage = 0.0;
  double repInteraction = 0.0;
  double repHist = 0.0;
  double repQDelivery = 0.0;

  double wBatteryUsed;
  double wStorageUsed;

  if (kDebugMode) {
    print("⚠️ hasHistory = $hasHistory");
  }

  if (!hasHistory) {
    // Adjust weights when only battery and storage are used
    double sum = weights[0] + weights[1]; // 0.28 + 0.14 = 0.42
    wBatteryUsed = weights[0] / sum; // ≈ 0.6666
    wStorageUsed = weights[1] / sum; // ≈ 0.3333

    repBattery = wBatteryUsed * normBattery;
    repStorage = wStorageUsed * normStorage;

    if (kDebugMode) {
      print("→ Adjusted weights (no history):");
      print("   Battery: $wBatteryUsed, Storage: $wStorageUsed");
    }
  } else {
    // Use full weights
    wBatteryUsed = weights[0];
    wStorageUsed = weights[1];

    repBattery = wBatteryUsed * normBattery;
    repStorage = wStorageUsed * normStorage;
    repInteraction = weights[2] * interactionScore;
    repHist = weights[3] * hist;
    repQDelivery = weights[4] * qDelivery;
  }

  reputation =
      repBattery + repStorage + repInteraction + repHist + repQDelivery;
  reputation = reputation.clamp(0.0, 1.0); // ensure within 0 to 1

  // Debug output
  if (kDebugMode) {
    print(">>> Detailed reputation calculation:");
    print("Battery ($wBatteryUsed * $normBattery) = $repBattery");
    print("Storage ($wStorageUsed * $normStorage) = $repStorage");
  }
  if (hasHistory) {
    if (kDebugMode) {
      print(
          "Interaction (${weights[2]} * $interactionScore) = $repInteraction");
      print("History     (${weights[3]} * $hist) = $repHist");
      print("QDelivery   (${weights[4]} * $qDelivery) = $repQDelivery");
    }
  }
  if (kDebugMode) {
    print("Total Reputation: $reputation");
  }

  canCooperate(); // Evaluate if reputation passes threshold (PL or SL)
  await _saveReputation();
}