import 'dart:math'; import 'question_source_preferences.dart'; import 'questions_db.dart'; /// Picks the next question source randomly matching configured mix percentages. abstract final class QuestionSourceMix { /// Source id selected using weighted random selection based on configured mix ratios. static String pickNextSourceId({ required Map effectiveMixPercent, required Map deliveredCounts, Random? random, }) { if (effectiveMixPercent.isEmpty) { return 'market_history'; } final int totalWeight = effectiveMixPercent.values.fold(0, (int a, int b) => a + b); if (totalWeight <= 0) { return effectiveMixPercent.keys.first; } // If one source has 100% of the active weight, bypass the random roll completely. for (final MapEntry entry in effectiveMixPercent.entries) { if (entry.value == totalWeight) { return entry.key; } } final Random rng = random ?? Random(); var roll = rng.nextInt(totalWeight); for (final MapEntry entry in effectiveMixPercent.entries) { roll -= entry.value; if (roll < 0) { return entry.key; } } return effectiveMixPercent.keys.first; } static Map effectiveMixFromResolved( List prefs, ) { return QuestionSourcePreferences.effectiveMix(prefs); } /// Orders unanswered rows so [preferredSourceId] is shown first (stable FIFO within source). static List> orderUnansweredByPreferredSource( List> rows, { required String preferredSourceId, }) { if (rows.length <= 1) { return rows; } final List> preferred = >[]; final List> rest = >[]; for (final Map row in rows) { if (QuestionsDb.resolveSourceId(row) == preferredSourceId) { preferred.add(row); } else { rest.add(row); } } return >[...preferred, ...rest]; } }