/// Domain Entity: Notification
///
/// Represents a notification sent to a user.
library;

/// Notification Entity
///
/// Contains information about a notification:
/// - Notification type and content
/// - Associated data
/// - Read and push status
class Notification {
  /// Unique notification identifier
  final String notificationId;

  /// User ID receiving the notification
  final String userId;

  /// Notification type (order, loyalty, promotion, system, etc.)
  final String type;

  /// Notification title
  final String title;

  /// Notification message/body
  final String message;

  /// Additional data (JSON object with context-specific information)
  final Map<String, dynamic>? data;

  /// Notification has been read
  final bool isRead;

  /// Push notification has been sent
  final bool isPushed;

  /// Notification creation timestamp
  final DateTime createdAt;

  /// Read timestamp
  final DateTime? readAt;

  const Notification({
    required this.notificationId,
    required this.userId,
    required this.type,
    required this.title,
    required this.message,
    this.data,
    required this.isRead,
    required this.isPushed,
    required this.createdAt,
    this.readAt,
  });

  /// Check if notification is unread
  bool get isUnread => !isRead;

  /// Check if notification is order-related
  bool get isOrderNotification => type.toLowerCase().contains('order');

  /// Check if notification is loyalty-related
  bool get isLoyaltyNotification =>
      type.toLowerCase().contains('loyalty') ||
      type.toLowerCase().contains('points');

  /// Check if notification is promotion-related
  bool get isPromotionNotification =>
      type.toLowerCase().contains('promotion') ||
      type.toLowerCase().contains('discount');

  /// Check if notification is system-related
  bool get isSystemNotification => type.toLowerCase().contains('system');

  /// Get related entity ID from data
  String? get relatedEntityId {
    if (data == null) return null;
    return data!['entity_id'] as String? ??
        data!['order_id'] as String? ??
        data!['quote_id'] as String?;
  }

  /// Get related entity type from data
  String? get relatedEntityType {
    if (data == null) return null;
    return data!['entity_type'] as String?;
  }

  /// Get time since notification was created
  Duration get timeSinceCreated {
    return DateTime.now().difference(createdAt);
  }

  /// Check if notification is recent (less than 24 hours)
  bool get isRecent {
    return timeSinceCreated.inHours < 24;
  }

  /// Check if notification is old (more than 7 days)
  bool get isOld {
    return timeSinceCreated.inDays > 7;
  }

  /// Get formatted time ago text (Vietnamese)
  String get formattedTimeAgo {
    final duration = timeSinceCreated;

    if (duration.inMinutes < 1) {
      return 'Vừa xong';
    } else if (duration.inMinutes < 60) {
      return '${duration.inMinutes} phút trước';
    } else if (duration.inHours < 24) {
      return '${duration.inHours} giờ trước';
    } else if (duration.inDays == 1) {
      return 'Hôm qua';
    } else if (duration.inDays < 7) {
      return '${duration.inDays} ngày trước';
    } else if (duration.inDays < 30) {
      final weeks = (duration.inDays / 7).floor();
      return '$weeks tuần trước';
    } else if (duration.inDays < 365) {
      final months = (duration.inDays / 30).floor();
      return '$months tháng trước';
    } else {
      final years = (duration.inDays / 365).floor();
      return '$years năm trước';
    }
  }

  /// Copy with method for immutability
  Notification copyWith({
    String? notificationId,
    String? userId,
    String? type,
    String? title,
    String? message,
    Map<String, dynamic>? data,
    bool? isRead,
    bool? isPushed,
    DateTime? createdAt,
    DateTime? readAt,
  }) {
    return Notification(
      notificationId: notificationId ?? this.notificationId,
      userId: userId ?? this.userId,
      type: type ?? this.type,
      title: title ?? this.title,
      message: message ?? this.message,
      data: data ?? this.data,
      isRead: isRead ?? this.isRead,
      isPushed: isPushed ?? this.isPushed,
      createdAt: createdAt ?? this.createdAt,
      readAt: readAt ?? this.readAt,
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is Notification &&
        other.notificationId == notificationId &&
        other.userId == userId &&
        other.type == type &&
        other.title == title &&
        other.message == message &&
        other.isRead == isRead &&
        other.isPushed == isPushed;
  }

  @override
  int get hashCode {
    return Object.hash(
      notificationId,
      userId,
      type,
      title,
      message,
      isRead,
      isPushed,
    );
  }

  @override
  String toString() {
    return 'Notification(notificationId: $notificationId, type: $type, '
        'title: $title, isRead: $isRead, createdAt: $createdAt)';
  }
}
