import 'package:hive/hive.dart'; import 'menu_model.dart'; part 'recommendation_model.g.dart'; @HiveType(typeId: 3) class RecommendationModel extends HiveObject { @HiveField(0) String id; @HiveField(1) String userId; @HiveField(2) List recommendations; @HiveField(3) String originalMenuText; @HiveField(4) String? menuImageUrl; @HiveField(5) String prompt; @HiveField(6) String aiResponse; @HiveField(7) double confidence; @HiveField(8) DateTime createdAt; @HiveField(9) bool isFavorite; @HiveField(10) String sessionId; @HiveField(11) String? selectedMenuName; @HiveField(12) List? menuImagePaths; RecommendationModel({ required this.id, required this.userId, required this.recommendations, required this.originalMenuText, this.menuImageUrl, this.menuImagePaths, required this.prompt, required this.aiResponse, this.confidence = 0.0, required this.createdAt, this.isFavorite = false, required this.sessionId, this.selectedMenuName, }); factory RecommendationModel.fromJson(Map json) { return RecommendationModel( id: json['id'] as String, userId: json['userId'] as String, recommendations: (json['recommendations'] as List) .map((e) => MenuRecommendation.fromJson(e as Map)) .toList(), originalMenuText: json['originalMenuText'] as String, menuImageUrl: json['menuImageUrl'] as String?, menuImagePaths: (json['menuImagePaths'] as List?) ?.map((e) => e as String) .toList(), prompt: json['prompt'] as String, aiResponse: json['aiResponse'] as String, confidence: (json['confidence'] as num?)?.toDouble() ?? 0.0, createdAt: DateTime.parse(json['createdAt'] as String), isFavorite: json['isFavorite'] as bool? ?? false, sessionId: json['sessionId'] as String, selectedMenuName: json['selectedMenuName'] as String?, ); } Map toJson() { return { 'id': id, 'userId': userId, 'recommendations': recommendations.map((e) => e.toJson()).toList(), 'originalMenuText': originalMenuText, 'menuImageUrl': menuImageUrl, 'menuImagePaths': menuImagePaths, 'prompt': prompt, 'aiResponse': aiResponse, 'confidence': confidence, 'createdAt': createdAt.toIso8601String(), 'isFavorite': isFavorite, 'sessionId': sessionId, 'selectedMenuName': selectedMenuName, }; } RecommendationModel copyWith({ String? id, String? userId, List? recommendations, String? originalMenuText, String? menuImageUrl, List? menuImagePaths, String? prompt, String? aiResponse, double? confidence, DateTime? createdAt, bool? isFavorite, String? sessionId, String? selectedMenuName, }) { return RecommendationModel( id: id ?? this.id, userId: userId ?? this.userId, recommendations: recommendations ?? this.recommendations, originalMenuText: originalMenuText ?? this.originalMenuText, menuImageUrl: menuImageUrl ?? this.menuImageUrl, menuImagePaths: menuImagePaths ?? this.menuImagePaths, prompt: prompt ?? this.prompt, aiResponse: aiResponse ?? this.aiResponse, confidence: confidence ?? this.confidence, createdAt: createdAt ?? this.createdAt, isFavorite: isFavorite ?? this.isFavorite, sessionId: sessionId ?? this.sessionId, selectedMenuName: selectedMenuName ?? this.selectedMenuName, ); } List get topRecommendations { final sorted = List.from(recommendations); sorted.sort((a, b) => b.score.compareTo(a.score)); return sorted.take(3).toList(); } String get formattedDate { final now = DateTime.now(); final difference = now.difference(createdAt); if (difference.inDays > 0) { return '${difference.inDays} hari yang lalu'; } else if (difference.inHours > 0) { return '${difference.inHours} jam yang lalu'; } else if (difference.inMinutes > 0) { return '${difference.inMinutes} menit yang lalu'; } else { return 'Baru saja'; } } } @HiveType(typeId: 4) class MenuRecommendation extends HiveObject { @HiveField(0) String menuName; @HiveField(1) String description; @HiveField(2) double price; @HiveField(3) String reason; @HiveField(4) double score; @HiveField(5) List tags; @HiveField(6) String category; @HiveField(7) String? imageUrl; @HiveField(8) bool isRecommended; @HiveField(9) String? slotType; MenuRecommendation({ required this.menuName, required this.description, required this.price, required this.reason, this.score = 0.0, this.tags = const [], required this.category, this.imageUrl, this.isRecommended = true, this.slotType, }); factory MenuRecommendation.fromJson(Map json) { return MenuRecommendation( menuName: json['menuName'] as String, description: json['description'] as String, price: (json['price'] as num).toDouble(), reason: json['reason'] as String, score: (json['score'] as num?)?.toDouble() ?? 0.0, tags: List.from(json['tags'] ?? []), category: json['category'] as String, imageUrl: json['imageUrl'] as String?, isRecommended: json['isRecommended'] as bool? ?? true, slotType: json['slotType'] as String?, ); } Map toJson() { return { 'menuName': menuName, 'description': description, 'price': price, 'reason': reason, 'score': score, 'tags': tags, 'category': category, 'imageUrl': imageUrl, 'isRecommended': isRecommended, 'slotType': slotType, }; } MenuRecommendation copyWith({ String? menuName, String? description, double? price, String? reason, double? score, List? tags, String? category, String? imageUrl, bool? isRecommended, String? slotType, }) { return MenuRecommendation( menuName: menuName ?? this.menuName, description: description ?? this.description, price: price ?? this.price, reason: reason ?? this.reason, score: score ?? this.score, tags: tags ?? this.tags, category: category ?? this.category, imageUrl: imageUrl ?? this.imageUrl, isRecommended: isRecommended ?? this.isRecommended, slotType: slotType ?? this.slotType, ); } String get formattedPrice { return 'Rp ${price.toStringAsFixed(0).replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]}.')}'; } int get starRating { return (score * 5).round().clamp(1, 5); } String get scorePercentage { return '${(score * 100).toStringAsFixed(0)}%'; } }