/// Domain Entity: Product
///
/// Pure business entity representing a product in the catalog.
/// This entity is framework-independent and contains only business logic.
library;

/// Product Entity
///
/// Represents a tile/construction product in the application.
/// Used across all layers but originates in the domain layer.
class Product {

  const Product({
    required this.productId,
    required this.name,
    this.description,
    required this.basePrice,
    required this.images,
    required this.thumbnail,
    required this.imageCaptions,
    this.customLink360,
    required this.specifications,
    this.itemGroupName,
    this.brand,
    this.conversionOfSm,
    this.introAttributes,
    required this.isActive,
    required this.isFeatured,
    this.erpnextItemCode,
    required this.createdAt,
    required this.updatedAt,
  });
  /// Unique identifier
  final String productId;

  /// Product name (Vietnamese)
  final String name;

  /// Product description
  final String? description;

  /// Base price per unit (VND)
  final double basePrice;

  /// Product images (URLs)
  final List<String> images;

  /// Thumbnail image URL
  final String thumbnail;

  /// Image captions
  final Map<String, String> imageCaptions;

  /// Custom 360-degree view link
  final String? customLink360;

  /// Product specifications
  final Map<String, dynamic> specifications;

  /// Item group name (from ERPNext)
  final String? itemGroupName;

  /// Brand name
  final String? brand;

  /// Conversion factor for Square Meter UOM (tiles per m²)
  /// Used to calculate: Số viên = Số lượng × conversionOfSm
  final double? conversionOfSm;

  /// Intro attributes (quick reference)
  /// List of maps with 'code' and 'value' keys
  /// Example: [{"code": "Size", "value": "120x120"}, {"code": "UOM", "value": "2 viên/hộp"}]
  final List<Map<String, String>>? introAttributes;

  /// Product is active
  final bool isActive;

  /// Product is featured
  final bool isFeatured;

  /// ERPNext item code
  final String? erpnextItemCode;

  /// Created date
  final DateTime createdAt;

  /// Last updated date
  final DateTime updatedAt;

  /// Get primary image URL
  String? get primaryImage => images.isNotEmpty ? images.first : null;

  /// Alias for primaryImage (used by UI widgets)
  String get imageUrl => primaryImage ?? '';

  /// Category ID (alias for itemGroupName field)
  String? get categoryId => itemGroupName;

  /// Check if product has 360 view
  bool get has360View => customLink360 != null && customLink360!.isNotEmpty;

  /// Check if product has multiple images
  bool get hasMultipleImages => images.length > 1;

  /// Check if product is on sale
  /// TODO: Implement sale price logic when backend supports it
  bool get isOnSale => false;

  /// Discount percentage
  /// TODO: Calculate from salePrice when backend supports it
  int get discountPercentage => 0;

  /// Effective price (considering sales)
  /// TODO: Use salePrice when backend supports it
  double get effectivePrice => basePrice;

  /// Check if product is low stock
  /// TODO: Implement stock tracking when backend supports it
  bool get isLowStock => false;

  /// Get specification value by key
  String? getSpecification(String key) {
    return specifications[key]?.toString();
  }

  /// Get intro attribute value by code
  String? getIntroAttribute(String code) {
    if (introAttributes == null) return null;

    try {
      final attr = introAttributes!.firstWhere(
        (attr) => attr['code']?.toLowerCase() == code.toLowerCase(),
      );
      return attr['value'];
    } catch (e) {
      return null;
    }
  }

  /// Copy with method for creating modified copies
  Product copyWith({
    String? productId,
    String? name,
    String? description,
    double? basePrice,
    List<String>? images,
    String? thumbnail,
    Map<String, String>? imageCaptions,
    String? customLink360,
    Map<String, dynamic>? specifications,
    String? itemGroupName,
    String? brand,
    double? conversionOfSm,
    List<Map<String, String>>? introAttributes,
    bool? isActive,
    bool? isFeatured,
    String? erpnextItemCode,
    DateTime? createdAt,
    DateTime? updatedAt,
  }) {
    return Product(
      productId: productId ?? this.productId,
      name: name ?? this.name,
      description: description ?? this.description,
      basePrice: basePrice ?? this.basePrice,
      images: images ?? this.images,
      thumbnail: thumbnail ?? this.thumbnail,
      imageCaptions: imageCaptions ?? this.imageCaptions,
      customLink360: customLink360 ?? this.customLink360,
      specifications: specifications ?? this.specifications,
      itemGroupName: itemGroupName ?? this.itemGroupName,
      brand: brand ?? this.brand,
      conversionOfSm: conversionOfSm ?? this.conversionOfSm,
      introAttributes: introAttributes ?? this.introAttributes,
      isActive: isActive ?? this.isActive,
      isFeatured: isFeatured ?? this.isFeatured,
      erpnextItemCode: erpnextItemCode ?? this.erpnextItemCode,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

  @override
  String toString() {
    return 'Product(productId: $productId, name: $name, basePrice: $basePrice, '
        'itemGroupName: $itemGroupName, isActive: $isActive, isFeatured: $isFeatured)';
  }

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

    return other is Product &&
        other.productId == productId &&
        other.name == name &&
        other.description == description &&
        other.basePrice == basePrice &&
        other.itemGroupName == itemGroupName &&
        other.brand == brand &&
        other.isActive == isActive &&
        other.isFeatured == isFeatured &&
        other.erpnextItemCode == erpnextItemCode;
  }

  @override
  int get hashCode {
    return Object.hash(
      productId,
      name,
      description,
      basePrice,
      itemGroupName,
      brand,
      isActive,
      isFeatured,
      erpnextItemCode,
    );
  }
}
