/// Domain Entity: Gift Catalog
///
/// Represents a redeemable gift in the loyalty program catalog.
library;

/// Gift category enum
enum GiftCategory {
  /// Voucher gift
  voucher,

  /// Physical product
  product,

  /// Service
  service,

  /// Discount coupon
  discount,

  /// Other type
  other;

  /// Get display name for category
  String get displayName {
    switch (this) {
      case GiftCategory.voucher:
        return 'Voucher';
      case GiftCategory.product:
        return 'Product';
      case GiftCategory.service:
        return 'Service';
      case GiftCategory.discount:
        return 'Discount';
      case GiftCategory.other:
        return 'Other';
    }
  }
}

/// Gift Catalog Entity
///
/// Contains information about a redeemable gift:
/// - Gift details (name, description, image)
/// - Pricing in points
/// - Availability
/// - Terms and conditions
class GiftCatalog {
  /// Unique catalog item identifier
  final String catalogId;

  /// Gift name
  final String name;

  /// Gift description
  final String? description;

  /// Gift image URL
  final String? imageUrl;

  /// Gift category
  final GiftCategory category;

  /// Points cost to redeem
  final int pointsCost;

  /// Cash value equivalent
  final double? cashValue;

  /// Quantity available for redemption
  final int quantityAvailable;

  /// Quantity already redeemed
  final int quantityRedeemed;

  /// Terms and conditions
  final String? termsConditions;

  /// Gift is active and available
  final bool isActive;

  /// Valid from date
  final DateTime? validFrom;

  /// Valid until date
  final DateTime? validUntil;

  /// Creation timestamp
  final DateTime createdAt;

  /// Last update timestamp
  final DateTime updatedAt;

  const GiftCatalog({
    required this.catalogId,
    required this.name,
    this.description,
    this.imageUrl,
    required this.category,
    required this.pointsCost,
    this.cashValue,
    required this.quantityAvailable,
    required this.quantityRedeemed,
    this.termsConditions,
    required this.isActive,
    this.validFrom,
    this.validUntil,
    required this.createdAt,
    required this.updatedAt,
  });

  /// Check if gift is available for redemption
  bool get isAvailable => isActive && quantityRemaining > 0 && isCurrentlyValid;

  /// Get remaining quantity
  int get quantityRemaining => quantityAvailable - quantityRedeemed;

  /// Check if gift is in stock
  bool get isInStock => quantityRemaining > 0;

  /// Check if gift is currently valid (date range)
  bool get isCurrentlyValid {
    final now = DateTime.now();
    if (validFrom != null && now.isBefore(validFrom!)) return false;
    if (validUntil != null && now.isAfter(validUntil!)) return false;
    return true;
  }

  /// Check if gift is coming soon
  bool get isComingSoon {
    if (validFrom == null) return false;
    return DateTime.now().isBefore(validFrom!);
  }

  /// Check if gift has expired
  bool get hasExpired {
    if (validUntil == null) return false;
    return DateTime.now().isAfter(validUntil!);
  }

  /// Get redemption percentage
  double get redemptionPercentage {
    if (quantityAvailable == 0) return 0;
    return (quantityRedeemed / quantityAvailable) * 100;
  }

  /// Copy with method for immutability
  GiftCatalog copyWith({
    String? catalogId,
    String? name,
    String? description,
    String? imageUrl,
    GiftCategory? category,
    int? pointsCost,
    double? cashValue,
    int? quantityAvailable,
    int? quantityRedeemed,
    String? termsConditions,
    bool? isActive,
    DateTime? validFrom,
    DateTime? validUntil,
    DateTime? createdAt,
    DateTime? updatedAt,
  }) {
    return GiftCatalog(
      catalogId: catalogId ?? this.catalogId,
      name: name ?? this.name,
      description: description ?? this.description,
      imageUrl: imageUrl ?? this.imageUrl,
      category: category ?? this.category,
      pointsCost: pointsCost ?? this.pointsCost,
      cashValue: cashValue ?? this.cashValue,
      quantityAvailable: quantityAvailable ?? this.quantityAvailable,
      quantityRedeemed: quantityRedeemed ?? this.quantityRedeemed,
      termsConditions: termsConditions ?? this.termsConditions,
      isActive: isActive ?? this.isActive,
      validFrom: validFrom ?? this.validFrom,
      validUntil: validUntil ?? this.validUntil,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

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

    return other is GiftCatalog &&
        other.catalogId == catalogId &&
        other.name == name &&
        other.category == category &&
        other.pointsCost == pointsCost &&
        other.isActive == isActive;
  }

  @override
  int get hashCode {
    return Object.hash(catalogId, name, category, pointsCost, isActive);
  }

  @override
  String toString() {
    return 'GiftCatalog(catalogId: $catalogId, name: $name, category: $category, '
        'pointsCost: $pointsCost, quantityRemaining: $quantityRemaining, '
        'isAvailable: $isAvailable)';
  }
}
