/// Domain Entity: Redeemed Gift
///
/// Represents a gift that has been redeemed by a user.
library;

import 'gift_catalog.dart';

/// Gift status enum
enum GiftStatus {
  /// Gift is active and can be used
  active,

  /// Gift has been used
  used,

  /// Gift has expired
  expired,

  /// Gift has been cancelled
  cancelled;

  /// Get display name for status
  String get displayName {
    switch (this) {
      case GiftStatus.active:
        return 'Active';
      case GiftStatus.used:
        return 'Used';
      case GiftStatus.expired:
        return 'Expired';
      case GiftStatus.cancelled:
        return 'Cancelled';
    }
  }
}

/// Redeemed Gift Entity
///
/// Contains information about a redeemed gift:
/// - Gift details
/// - Voucher code and QR code
/// - Usage tracking
/// - Expiry dates
class RedeemedGift {
  /// Unique gift identifier
  final String giftId;

  /// User ID who redeemed the gift
  final String userId;

  /// Catalog ID of the gift
  final String catalogId;

  /// Gift name (snapshot at redemption time)
  final String name;

  /// Gift description
  final String? description;

  /// Voucher code
  final String? voucherCode;

  /// QR code image URL
  final String? qrCodeImage;

  /// Gift type/category
  final GiftCategory giftType;

  /// Points cost (snapshot at redemption time)
  final int pointsCost;

  /// Cash value (snapshot at redemption time)
  final double? cashValue;

  /// Expiry date
  final DateTime? expiryDate;

  /// Gift status
  final GiftStatus status;

  /// Redemption timestamp
  final DateTime redeemedAt;

  /// Usage timestamp
  final DateTime? usedAt;

  /// Location where gift was used
  final String? usedLocation;

  /// Reference number when used (e.g., order ID)
  final String? usedReference;

  const RedeemedGift({
    required this.giftId,
    required this.userId,
    required this.catalogId,
    required this.name,
    this.description,
    this.voucherCode,
    this.qrCodeImage,
    required this.giftType,
    required this.pointsCost,
    this.cashValue,
    this.expiryDate,
    required this.status,
    required this.redeemedAt,
    this.usedAt,
    this.usedLocation,
    this.usedReference,
  });

  /// Check if gift is active
  bool get isActive => status == GiftStatus.active;

  /// Check if gift is used
  bool get isUsed => status == GiftStatus.used;

  /// Check if gift is expired
  bool get isExpired =>
      status == GiftStatus.expired ||
      (expiryDate != null && DateTime.now().isAfter(expiryDate!));

  /// Check if gift can be used
  bool get canBeUsed => isActive && !isExpired;

  /// Check if gift is expiring soon (within 7 days)
  bool get isExpiringSoon {
    if (expiryDate == null || isExpired) return false;
    final daysUntilExpiry = expiryDate!.difference(DateTime.now()).inDays;
    return daysUntilExpiry > 0 && daysUntilExpiry <= 7;
  }

  /// Get days until expiry
  int? get daysUntilExpiry {
    if (expiryDate == null) return null;
    final days = expiryDate!.difference(DateTime.now()).inDays;
    return days > 0 ? days : 0;
  }

  /// Copy with method for immutability
  RedeemedGift copyWith({
    String? giftId,
    String? userId,
    String? catalogId,
    String? name,
    String? description,
    String? voucherCode,
    String? qrCodeImage,
    GiftCategory? giftType,
    int? pointsCost,
    double? cashValue,
    DateTime? expiryDate,
    GiftStatus? status,
    DateTime? redeemedAt,
    DateTime? usedAt,
    String? usedLocation,
    String? usedReference,
  }) {
    return RedeemedGift(
      giftId: giftId ?? this.giftId,
      userId: userId ?? this.userId,
      catalogId: catalogId ?? this.catalogId,
      name: name ?? this.name,
      description: description ?? this.description,
      voucherCode: voucherCode ?? this.voucherCode,
      qrCodeImage: qrCodeImage ?? this.qrCodeImage,
      giftType: giftType ?? this.giftType,
      pointsCost: pointsCost ?? this.pointsCost,
      cashValue: cashValue ?? this.cashValue,
      expiryDate: expiryDate ?? this.expiryDate,
      status: status ?? this.status,
      redeemedAt: redeemedAt ?? this.redeemedAt,
      usedAt: usedAt ?? this.usedAt,
      usedLocation: usedLocation ?? this.usedLocation,
      usedReference: usedReference ?? this.usedReference,
    );
  }

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

    return other is RedeemedGift &&
        other.giftId == giftId &&
        other.userId == userId &&
        other.catalogId == catalogId &&
        other.voucherCode == voucherCode &&
        other.status == status;
  }

  @override
  int get hashCode {
    return Object.hash(giftId, userId, catalogId, voucherCode, status);
  }

  @override
  String toString() {
    return 'RedeemedGift(giftId: $giftId, name: $name, voucherCode: $voucherCode, '
        'status: $status, redeemedAt: $redeemedAt)';
  }
}
