import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:uuid/uuid.dart'; import '../models/task_model.dart'; import '../core/firestore_service.dart'; import '../core/local_storage_service.dart'; import '../core/deepseek_service.dart'; import '../core/notification_service.dart'; // Provider для текущего пользователя (заглушка пока нет auth) final currentUserIdProvider = Provider((ref) { // TODO: Заменить на реального пользователя из Firebase Auth return null; // Пока нет авторизации }); // Provider для списка всех задач final tasksProvider = StateNotifierProvider>>((ref) { return TasksNotifier(ref); }); // Provider для задач конкретного проекта final tasksByProjectProvider = Provider.family>, String>((ref, projectId) { final tasks = ref.watch(tasksProvider); return tasks.when( data: (allTasks) => AsyncValue.data( allTasks.where((t) => t.projectId == projectId).toList()), loading: () => const AsyncValue.loading(), error: (e, st) => AsyncValue.error(e, st), ); }); // Provider для задач пользователя final tasksByUserProvider = Provider.family>, String>((ref, userId) { final tasks = ref.watch(tasksProvider); return tasks.when( data: (allTasks) => AsyncValue.data(allTasks.where((t) => t.assigneeId == userId).toList()), loading: () => const AsyncValue.loading(), error: (e, st) => AsyncValue.error(e, st), ); }); // Stream provider для задач в реальном времени final tasksStreamProvider = StreamProvider.family, String?>((ref, projectId) { return firestoreService.watchTasks(projectId); }); class TasksNotifier extends StateNotifier>> { final Ref ref; StreamSubscription? _subscription; TasksNotifier(this.ref) : super(const AsyncValue.loading()) { _loadTasks(); } @override void dispose() { _subscription?.cancel(); super.dispose(); } // Загрузка задач Future _loadTasks() async { try { // Сначала загружаем из локального хранилища (офлайн режим) final localTasks = localStorageService.getTasks(); state = AsyncValue.data(localTasks); // Подписываемся на обновления из Firestore final currentUserId = ref.read(currentUserIdProvider); _subscription = firestoreService.watchTasks(null).listen((remoteTasks) async { // Сохраняем локально для офлайн режима await localStorageService.syncWithRemote(remoteTasks); // Обновляем состояние state = AsyncValue.data(remoteTasks); }, onError: (error, stackTrace) { // Если ошибка Firestore, используем локальные данные print('Firestore error: $error'); final localTasks = localStorageService.getTasks(); state = AsyncValue.data(localTasks); }); } catch (e, st) { state = AsyncValue.error(e, st); } } // Создание задачи Future createTask({ required String title, String? description, required String projectId, String? parentTaskId, TaskPriority priority = TaskPriority.medium, DateTime? dueDate, int estimatedHours = 0, String? assigneeId, bool sendNotification = true, }) async { try { final currentUserId = ref.read(currentUserIdProvider); final task = TaskModel( id: const Uuid().v4(), title: title, description: description, projectId: projectId, parentTaskId: parentTaskId, priority: priority, dueDate: dueDate, estimatedHours: estimatedHours, assigneeId: assigneeId ?? currentUserId, creatorId: currentUserId, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); // Сохраняем локально (для офлайн режима) await localStorageService.saveTask(task); // Сохраняем в Firestore try { await firestoreService.createTask(task); } catch (e) { print('Firestore save failed, saved locally only: $e'); } // Отправляем уведомление if (sendNotification) { await notificationService.showNewTaskNotification( taskTitle: title, taskId: task.id, ); } // Планируем напоминание о дедлайне if (dueDate != null) { await scheduleDeadlineReminder(task); } // Обновляем состояние final currentTasks = state.value ?? []; state = AsyncValue.data([...currentTasks, task]); return task; } catch (e, st) { state = AsyncValue.error(e, st); rethrow; } } // Обновление задачи Future updateTask( String taskId, { String? title, String? description, TaskStatus? status, TaskPriority? priority, DateTime? dueDate, String? assigneeId, Map? aiMetadata, }) async { try { final currentTasks = state.value ?? []; final taskIndex = currentTasks.indexWhere((t) => t.id == taskId); if (taskIndex == -1) throw Exception('Task not found'); final oldTask = currentTasks[taskIndex]; final updatedTask = oldTask.copyWith( title: title ?? oldTask.title, description: description ?? oldTask.description, status: status ?? oldTask.status, priority: priority ?? oldTask.priority, dueDate: dueDate ?? oldTask.dueDate, assigneeId: assigneeId ?? oldTask.assigneeId, aiMetadata: aiMetadata ?? oldTask.aiMetadata, updatedAt: DateTime.now(), ); // Сохраняем локально await localStorageService.saveTask(updatedTask); // Сохраняем в Firestore try { await firestoreService.updateTask(updatedTask); } catch (e) { print('Firestore update failed, saved locally only: $e'); } // Обновляем состояние currentTasks[taskIndex] = updatedTask; state = AsyncValue.data(List.from(currentTasks)); } catch (e, st) { state = AsyncValue.error(e, st); rethrow; } } // Удаление задачи Future deleteTask(String taskId) async { try { // Удаляем локально await localStorageService.deleteTask(taskId); // Удаляем из Firestore try { await firestoreService.deleteTask(taskId); } catch (e) { print('Firestore delete failed, deleted locally only: $e'); } // Обновляем состояние final currentTasks = state.value ?? []; currentTasks.removeWhere((t) => t.id == taskId); state = AsyncValue.data(List.from(currentTasks)); } catch (e, st) { state = AsyncValue.error(e, st); rethrow; } } // AI: Генерация подзадач Future> generateSubtasksWithAI({ required String title, required String description, required String projectId, String? parentTaskId, }) async { try { final subtasksData = await deepSeekService.generateSubtasks( title: title, description: description, ); final subtasks = []; for (final subtaskData in subtasksData) { final subtask = await createTask( title: subtaskData['title'] ?? '', description: subtaskData['description'], projectId: projectId, parentTaskId: parentTaskId, estimatedHours: subtaskData['estimatedHours'] ?? 0, ); subtasks.add(subtask); } return subtasks; } catch (e) { rethrow; } } // AI: Приоритизация задачи Future prioritizeTaskWithAI({ required String title, required String description, DateTime? dueDate, }) async { return await deepSeekService.prioritizeTask( title: title, description: description, dueDate: dueDate, ); } // AI: Генерация описания Future generateDescriptionWithAI({ required String title, String? context, }) async { return await deepSeekService.generateTaskDescription( title: title, context: context, ); } // Фильтрация задач по статусу List filterByStatus(List tasks, TaskStatus status) { return tasks.where((t) => t.status == status).toList(); } // Фильтрация задач по приоритету List filterByPriority( List tasks, TaskPriority priority) { return tasks.where((t) => t.priority == priority).toList(); } // Просроченные задачи List getOverdueTasks(List tasks) { return tasks.where((t) => t.isOverdue).toList(); } // Завершение задачи Future completeTask(String taskId) async { await updateTask( taskId, status: TaskStatus.done, ); } // Возобновление задачи Future reopenTask(String taskId) async { await updateTask( taskId, status: TaskStatus.todo, ); } // Планирование напоминания о дедлайне Future scheduleDeadlineReminder(TaskModel task) async { if (task.dueDate == null) return; final now = DateTime.now(); final dueDate = task.dueDate!; // Напоминание за 24 часа if (dueDate.difference(now).inHours > 24) { final reminder24h = dueDate.subtract(const Duration(hours: 24)); if (reminder24h.isAfter(now)) { await notificationService.scheduleNotification( id: '${task.id}_24h'.hashCode, title: '🔔 Напоминание о задаче', body: 'Задача "${task.title}" должна быть выполнена завтра', scheduledDate: reminder24h, payload: task.id, ); } } // Напоминание за 1 час if (dueDate.difference(now).inHours > 1) { final reminder1h = dueDate.subtract(const Duration(hours: 1)); if (reminder1h.isAfter(now)) { await notificationService.scheduleNotification( id: '${task.id}_1h'.hashCode, title: '⏰ Скоро дедлайн!', body: 'Задача "${task.title}" должна быть выполнена через час', scheduledDate: reminder1h, payload: task.id, ); } } } // Отмена напоминаний о задаче Future cancelTaskReminders(String taskId) async { await notificationService.cancelNotification('${taskId}_24h'.hashCode); await notificationService.cancelNotification('${taskId}_1h'.hashCode); } }