part of 'relationship_repository.dart'; extension LocalRepositoryAiDigestOperations on LocalRepository { Future saveAiSuggestionDrafts(List drafts) async { if (drafts.isEmpty) { return; } final LocalDataState current = _requireState(); final Set existingKeys = current.aiSuggestionDrafts .map(_aiDraftDedupeKey) .toSet(); final List uniqueDrafts = drafts .where((AiSuggestionDraft draft) { if (!_personExists(current.people, draft.personId)) { return false; } return existingKeys.add(_aiDraftDedupeKey(draft)); }) .toList(growable: false); if (uniqueDrafts.isEmpty) { return; } await _setState( current.copyWith( aiSuggestionDrafts: [ ...uniqueDrafts, ...current.aiSuggestionDrafts, ], ), ); } Future acceptAiSuggestionDraft(String draftId) async { final LocalDataState current = _requireState(); final AiSuggestionDraft? draft = current.aiSuggestionDrafts .where((AiSuggestionDraft item) => item.id == draftId) .cast() .firstOrNull; if (draft == null || draft.status != AiSuggestionStatus.pending) { return; } if (!_personExists(current.people, draft.personId)) { await _setAiSuggestionStatus(draftId, AiSuggestionStatus.dismissed); return; } final DateTime now = DateTime.now(); final List drafts = current.aiSuggestionDrafts .map( (AiSuggestionDraft item) => item.id == draftId ? item.copyWith(status: AiSuggestionStatus.accepted) : item, ) .toList(growable: false); switch (draft.kind) { case AiSuggestionKind.giftIdea: case AiSuggestionKind.eventIdea: final RelationshipIdea idea = RelationshipIdea( id: 'i-${_uuid.v4()}', personId: draft.personId, type: draft.kind == AiSuggestionKind.giftIdea ? IdeaType.gift : IdeaType.event, title: draft.title, details: _aiDraftDetails(draft), createdAt: now, ); await _setState( current.copyWith( aiSuggestionDrafts: drafts, ideas: [idea, ...current.ideas], ), ); await _enqueueChange( _buildEnvelope( entityType: _ideaEntityType(idea.type), entityId: idea.id, op: ChangeOperation.upsert, payload: _ideaPayload(idea), ), ); case AiSuggestionKind.checkIn: final DashboardTask task = DashboardTask( id: 't-${_uuid.v4()}', title: draft.title, description: _aiDraftDetails(draft), when: draft.suggestedFor ?? now.add(const Duration(days: 1)), ); await _setState( current.copyWith( aiSuggestionDrafts: drafts, tasks: [task, ...current.tasks], ), ); case AiSuggestionKind.reminder: final ReminderRule reminder = ReminderRule( id: 'r-${_uuid.v4()}', personId: draft.personId, title: draft.title, cadence: ReminderCadence.weekly, nextAt: draft.suggestedFor ?? now.add(const Duration(days: 7)), ); await _setState( current.copyWith( aiSuggestionDrafts: drafts, reminders: [reminder, ...current.reminders], ), ); await _enqueueChange( _buildEnvelope( entityType: 'reminderRule', entityId: reminder.id, op: ChangeOperation.upsert, payload: _reminderPayload(reminder), ), ); } } Future dismissAiSuggestionDraft(String draftId) { return _setAiSuggestionStatus(draftId, AiSuggestionStatus.dismissed); } Future _setAiSuggestionStatus( String draftId, AiSuggestionStatus status, ) async { final LocalDataState current = _requireState(); final List drafts = current.aiSuggestionDrafts .map( (AiSuggestionDraft item) => item.id == draftId ? item.copyWith(status: status) : item, ) .toList(growable: false); await _setState(current.copyWith(aiSuggestionDrafts: drafts)); } } String _aiDraftDedupeKey(AiSuggestionDraft draft) { return [ draft.personId, draft.kind.name, draft.title.trim().toLowerCase(), draft.details.trim().toLowerCase(), ].join('|'); } String _aiDraftDetails(AiSuggestionDraft draft) { final String reason = draft.reason == null || draft.reason!.trim().isEmpty ? '' : '\n\nWhy: ${draft.reason!.trim()}'; return '${draft.details.trim()}$reason'.trim(); } extension on Iterable { T? get firstOrNull => isEmpty ? null : first; }