/// Domain Entity: Points Record
///
/// Represents a user-submitted invoice for points earning.
library;

/// Points record status enum
enum PointsStatus {
  /// Record submitted, pending review
  pending,

  /// Record approved, points awarded
  approved,

  /// Record rejected
  rejected;

  /// Get display name for status
  String get displayName {
    switch (this) {
      case PointsStatus.pending:
        return 'Chờ duyệt';
      case PointsStatus.approved:
        return 'Đã duyệt';
      case PointsStatus.rejected:
        return 'Bị từ chối';
    }
  }
}

/// Points Record Entity
///
/// Contains information about a user-submitted invoice:
/// - Invoice details
/// - Submission files/attachments
/// - Review status
/// - Points calculation
class PointsRecord {
  /// Unique record identifier
  final String recordId;

  /// User ID who submitted
  final String userId;

  /// Invoice number
  final String invoiceNumber;

  /// Store/vendor name
  final String storeName;

  /// Transaction date
  final DateTime transactionDate;

  /// Invoice amount
  final double invoiceAmount;

  /// Additional notes
  final String? notes;

  /// Attachment URLs (invoice photos, receipts)
  final List<String> attachments;

  /// Record status
  final PointsStatus status;

  /// Rejection reason (if rejected)
  final String? rejectReason;

  /// Points earned (if approved)
  final int? pointsEarned;

  /// Submission timestamp
  final DateTime submittedAt;

  /// Processing timestamp
  final DateTime? processedAt;

  /// ID of admin who processed
  final String? processedBy;

  const PointsRecord({
    required this.recordId,
    required this.userId,
    required this.invoiceNumber,
    required this.storeName,
    required this.transactionDate,
    required this.invoiceAmount,
    this.notes,
    required this.attachments,
    required this.status,
    this.rejectReason,
    this.pointsEarned,
    required this.submittedAt,
    this.processedAt,
    this.processedBy,
  });

  /// Check if record is pending review
  bool get isPending => status == PointsStatus.pending;

  /// Check if record is approved
  bool get isApproved => status == PointsStatus.approved;

  /// Check if record is rejected
  bool get isRejected => status == PointsStatus.rejected;

  /// Check if record has been processed
  bool get isProcessed => status != PointsStatus.pending;

  /// Check if record has attachments
  bool get hasAttachments => attachments.isNotEmpty;

  /// Get processing time duration
  Duration? get processingDuration {
    if (processedAt == null) return null;
    return processedAt!.difference(submittedAt);
  }

  /// Copy with method for immutability
  PointsRecord copyWith({
    String? recordId,
    String? userId,
    String? invoiceNumber,
    String? storeName,
    DateTime? transactionDate,
    double? invoiceAmount,
    String? notes,
    List<String>? attachments,
    PointsStatus? status,
    String? rejectReason,
    int? pointsEarned,
    DateTime? submittedAt,
    DateTime? processedAt,
    String? processedBy,
  }) {
    return PointsRecord(
      recordId: recordId ?? this.recordId,
      userId: userId ?? this.userId,
      invoiceNumber: invoiceNumber ?? this.invoiceNumber,
      storeName: storeName ?? this.storeName,
      transactionDate: transactionDate ?? this.transactionDate,
      invoiceAmount: invoiceAmount ?? this.invoiceAmount,
      notes: notes ?? this.notes,
      attachments: attachments ?? this.attachments,
      status: status ?? this.status,
      rejectReason: rejectReason ?? this.rejectReason,
      pointsEarned: pointsEarned ?? this.pointsEarned,
      submittedAt: submittedAt ?? this.submittedAt,
      processedAt: processedAt ?? this.processedAt,
      processedBy: processedBy ?? this.processedBy,
    );
  }

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

    return other is PointsRecord &&
        other.recordId == recordId &&
        other.userId == userId &&
        other.invoiceNumber == invoiceNumber &&
        other.invoiceAmount == invoiceAmount &&
        other.status == status;
  }

  @override
  int get hashCode {
    return Object.hash(recordId, userId, invoiceNumber, invoiceAmount, status);
  }

  @override
  String toString() {
    return 'PointsRecord(recordId: $recordId, invoiceNumber: $invoiceNumber, '
        'storeName: $storeName, invoiceAmount: $invoiceAmount, status: $status, '
        'pointsEarned: $pointsEarned)';
  }
}
