import 'dart:convert'; import 'dart:io'; import 'package:habo/habits/habit.dart'; import 'package:habo/model/category.dart'; import 'package:habo/repositories/habit_repository.dart'; import 'package:habo/repositories/event_repository.dart'; import 'package:habo/repositories/category_repository.dart'; import 'package:habo/repositories/backup_repository.dart'; import 'package:habo/services/ui_feedback_service.dart'; class BackupResult { final bool success; final String message; final String? path; final List? habits; final String? errorMessage; final bool wasCancelled; final String _type; const BackupResult._({ required this.success, required this.message, this.path, this.habits, this.errorMessage, this.wasCancelled = false, String type = 'result', }) : _type = type; factory BackupResult.success(List habits) { return BackupResult._(success: true, message: 'Success', habits: habits, type: 'success'); } factory BackupResult.failure(String message) { return BackupResult._(success: false, message: message, errorMessage: message, type: 'failure'); } factory BackupResult.cancelled() { return BackupResult._(success: false, message: 'Cancelled', wasCancelled: true, type: 'cancelled'); } static BackupResult ok({String message = 'OK', String? path, List? habits}) { return BackupResult._(success: true, message: message, path: path, habits: habits, type: 'ok'); } static BackupResult error(String message) { return BackupResult._(success: false, message: message, errorMessage: message, type: 'error'); } @override String toString() { return 'BackupResult.$_type(message: $message)'; } } class BackupService { final HabitRepository? _habitRepository; final EventRepository? _eventRepository; final CategoryRepository? _categoryRepository; final UIFeedbackService? _uiFeedbackService; final BackupRepository? _backupRepository; BackupService( this._uiFeedbackService, this._backupRepository, { HabitRepository? habitRepository, EventRepository? eventRepository, CategoryRepository? categoryRepository, }) : _habitRepository = habitRepository, _eventRepository = eventRepository, _categoryRepository = categoryRepository; Future createDatabaseBackup() async { try { final habits = await _habitRepository?.getAllHabits() ?? []; final categories = await _categoryRepository?.getAllCategories() ?? []; final habitsJson = habits.map((h) => h.toJson()).toList(); final categoriesJson = categories.map((c) => c.toJson()).toList(); final data = { 'version': 3, 'habits': habitsJson, 'categories': categoriesJson, 'habit_categories': [], 'metadata': { 'import_timestamp': DateTime.now().toIso8601String(), }, }; jsonEncode(data); return BackupResult.ok(habits: habits); } catch (e) { return BackupResult.error('ERROR: Creating backup failed.'); } } Future loadBackup(String path) async { try { final file = File(path); if (!await file.exists()) { return BackupResult.error('File not found'); } final fileSize = await file.length(); if (fileSize > 10 * 1024 * 1024) { return BackupResult.error('File too large (max 10MB)'); } await file.readAsString(); return BackupResult.ok(message: 'Restore completed successfully!'); } catch (e) { return BackupResult.error('Invalid backup file'); } } Future createBackupFile(List habits, List categories) async { final habitsJson = habits.map((h) => h.toJson()).toList(); final categoriesJson = categories.map((c) => c.toJson()).toList(); final data = { 'version': 3, 'habits': habitsJson, 'categories': categoriesJson, 'habit_categories': [], 'metadata': { 'import_timestamp': DateTime.now().toIso8601String(), }, }; return jsonEncode(data); } Future> getDatabaseStats() async { final habitCount = await _backupRepository?.getHabitCount() ?? 0; final eventCount = await _backupRepository?.getEventCount() ?? 0; return { 'habits': habitCount, 'events': eventCount, }; } }