import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:lunchpick/presentation/pages/calendar/widgets/visit_confirmation_dialog.dart'; import 'package:lunchpick/presentation/providers/restaurant_provider.dart'; /// 알림 payload 데이터 모델 class NotificationPayload { final String type; final String restaurantId; final String restaurantName; final DateTime recommendationTime; NotificationPayload({ required this.type, required this.restaurantId, required this.restaurantName, required this.recommendationTime, }); factory NotificationPayload.fromString(String payload) { try { final parts = payload.split('|'); if (parts.length < 4) { throw FormatException( 'Invalid payload format - expected 4 parts but got ${parts.length}: $payload', ); } // 각 필드 유효성 검증 if (parts[0].isEmpty) { throw FormatException('Type cannot be empty'); } if (parts[1].isEmpty) { throw FormatException('Restaurant ID cannot be empty'); } if (parts[2].isEmpty) { throw FormatException('Restaurant name cannot be empty'); } // DateTime 파싱 시도 DateTime? recommendationTime; try { recommendationTime = DateTime.parse(parts[3]); } catch (e) { throw FormatException('Invalid date format: ${parts[3]}. Error: $e'); } return NotificationPayload( type: parts[0], restaurantId: parts[1], restaurantName: parts[2], recommendationTime: recommendationTime, ); } catch (e) { // 더 상세한 오류 정보 제공 print('NotificationPayload parsing error: $e'); print('Original payload: $payload'); rethrow; } } String toString() { return '$type|$restaurantId|$restaurantName|${recommendationTime.toIso8601String()}'; } } /// 알림 핸들러 StateNotifier class NotificationHandlerNotifier extends StateNotifier> { final Ref _ref; NotificationHandlerNotifier(this._ref) : super(const AsyncValue.data(null)); /// 알림 클릭 처리 Future handleNotificationTap( BuildContext context, String? payload, ) async { if (payload == null || payload.isEmpty) { print('Notification payload is null or empty'); return; } print('Handling notification with payload: $payload'); try { // 기존 형식 (visit_reminder:restaurantName) 처리 if (payload.startsWith('visit_reminder:')) { final restaurantName = payload.substring(15); print('Legacy format - Restaurant name: $restaurantName'); // 맛집 이름으로 ID 찾기 final restaurantsAsync = await _ref.read(restaurantListProvider.future); final restaurant = restaurantsAsync.firstWhere( (r) => r.name == restaurantName, orElse: () => throw Exception('Restaurant not found: $restaurantName'), ); // 방문 확인 다이얼로그 표시 if (context.mounted) { await VisitConfirmationDialog.show( context: context, restaurantId: restaurant.id, restaurantName: restaurant.name, recommendationTime: DateTime.now().subtract( const Duration(hours: 2), ), ); } } else { // 새로운 형식의 payload 처리 print('Attempting to parse new format payload'); try { final notificationPayload = NotificationPayload.fromString(payload); print( 'Successfully parsed payload - Type: ${notificationPayload.type}, RestaurantId: ${notificationPayload.restaurantId}', ); if (notificationPayload.type == 'visit_reminder') { // 방문 확인 다이얼로그 표시 if (context.mounted) { final confirmed = await VisitConfirmationDialog.show( context: context, restaurantId: notificationPayload.restaurantId, restaurantName: notificationPayload.restaurantName, recommendationTime: notificationPayload.recommendationTime, ); // 확인 또는 취소 후 캘린더 화면으로 이동 if (context.mounted && confirmed != null) { context.go('/home?tab=calendar'); } } } } catch (parseError) { print('Failed to parse new format, attempting fallback parsing'); print('Parse error: $parseError'); // Fallback: 간단한 파싱 시도 if (payload.contains('|')) { final parts = payload.split('|'); if (parts.isNotEmpty && parts[0] == 'visit_reminder') { // 최소한 캘린더로 이동 if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('알림을 처리했습니다. 방문 기록을 확인해주세요.')), ); context.go('/home?tab=calendar'); } return; } } // 파싱 실패 시 원래 에러 다시 발생 rethrow; } } } catch (e, stackTrace) { print('Error handling notification: $e'); print('Stack trace: $stackTrace'); state = AsyncValue.error(e, stackTrace); // 에러 발생 시 기본적으로 캘린더 화면으로 이동 if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('알림 처리 중 오류가 발생했습니다: ${e.toString()}'), backgroundColor: Colors.red, ), ); context.go('/home?tab=calendar'); } } } } /// NotificationHandler Provider final notificationHandlerProvider = StateNotifierProvider>((ref) { return NotificationHandlerNotifier(ref); });