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<MenuRecommendation> 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<String>? 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<String, dynamic> 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<String, dynamic>))
          .toList(),
      originalMenuText: json['originalMenuText'] as String,
      menuImageUrl: json['menuImageUrl'] as String?,
      menuImagePaths: (json['menuImagePaths'] as List<dynamic>?)
          ?.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<String, dynamic> 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<MenuRecommendation>? recommendations,
    String? originalMenuText,
    String? menuImageUrl,
    List<String>? 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<MenuRecommendation> get topRecommendations {
    final sorted = List<MenuRecommendation>.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<String> 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<String, dynamic> 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<String>.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<String, dynamic> 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<String>? 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)}%';
  }
}
