/// Domain Entity: User
///
/// Represents a user account in the Worker application.
/// Contains authentication, profile, and loyalty information.
library;

/// User role enum
enum UserRole {
  /// Customer/worker user
  customer,

  /// Sales representative
  sales,

  /// System administrator
  admin,

  /// Accountant
  accountant,

  /// Designer
  designer,
}

/// User status enum
enum UserStatus {
  /// Account pending approval
  pending,

  /// Active account
  active,

  /// Suspended account
  suspended,

  /// Rejected account
  rejected,
}

/// Loyalty tier enum
enum LoyaltyTier {
  /// No tier
  none,

  /// Gold tier (entry level)
  gold,

  /// Platinum tier (mid level)
  platinum,

  /// Diamond tier (highest level)
  diamond;

  /// Get display name for tier
  String get displayName {
    switch (this) {
      case LoyaltyTier.none:
        return 'NONE';
      case LoyaltyTier.gold:
        return 'GOLD';
      case LoyaltyTier.platinum:
        return 'PLATINUM';
      case LoyaltyTier.diamond:
        return 'DIAMOND';
    }
  }
}

/// Company information
class CompanyInfo {
  /// Company name
  final String? name;

  /// Tax identification number
  final String? taxId;

  /// Company address
  final String? address;

  /// Business type
  final String? businessType;

  /// Business license number
  final String? licenseNumber;

  const CompanyInfo({
    this.name,
    this.taxId,
    this.address,
    this.businessType,
    this.licenseNumber,
  });

  /// Create from JSON map
  factory CompanyInfo.fromJson(Map<String, dynamic> json) {
    return CompanyInfo(
      name: json['name'] as String?,
      taxId: json['tax_id'] as String?,
      address: json['address'] as String?,
      businessType: json['business_type'] as String?,
      licenseNumber: json['license_number'] as String?,
    );
  }

  /// Convert to JSON map
  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'tax_id': taxId,
      'address': address,
      'business_type': businessType,
      'license_number': licenseNumber,
    };
  }
}

/// User Entity
///
/// Represents a complete user profile including:
/// - Authentication credentials
/// - Personal information
/// - Company details (if applicable)
/// - Loyalty program membership
/// - Referral information
class User {
  /// Unique user identifier
  final String userId;

  /// Phone number (used for login)
  final String phoneNumber;

  /// Full name
  final String fullName;

  /// Email address
  final String? email;

  /// User role
  final UserRole role;

  /// Account status
  final UserStatus status;

  /// Current loyalty tier
  final LoyaltyTier loyaltyTier;

  /// Total loyalty points
  final int totalPoints;

  /// Company information (optional)
  final CompanyInfo? companyInfo;

  /// CCCD/ID card number
  final String? cccd;

  /// Attachment URLs (ID cards, licenses, etc.)
  final List<String> attachments;

  /// Address
  final String? address;

  /// Avatar URL
  final String? avatarUrl;

  /// Referral code (unique for this user)
  final String? referralCode;

  /// ID of user who referred this user
  final String? referredBy;

  /// ERPNext customer ID
  final String? erpnextCustomerId;

  /// Account creation timestamp
  final DateTime createdAt;

  /// Last update timestamp
  final DateTime updatedAt;

  /// Last login timestamp
  final DateTime? lastLoginAt;

  const User({
    required this.userId,
    required this.phoneNumber,
    required this.fullName,
    this.email,
    required this.role,
    required this.status,
    required this.loyaltyTier,
    required this.totalPoints,
    this.companyInfo,
    this.cccd,
    required this.attachments,
    this.address,
    this.avatarUrl,
    this.referralCode,
    this.referredBy,
    this.erpnextCustomerId,
    required this.createdAt,
    required this.updatedAt,
    this.lastLoginAt,
  });

  /// Check if user is active
  bool get isActive => status == UserStatus.active;

  /// Check if user is pending approval
  bool get isPending => status == UserStatus.pending;

  /// Check if user has company info
  bool get hasCompanyInfo => companyInfo != null && companyInfo!.name != null;

  /// Check if user is an admin
  bool get isAdmin => role == UserRole.admin;

  /// Check if user is a customer
  bool get isCustomer => role == UserRole.customer;

  /// Get display name for user
  String get displayName => fullName;

  /// Copy with method for immutability
  User copyWith({
    String? userId,
    String? phoneNumber,
    String? fullName,
    String? email,
    UserRole? role,
    UserStatus? status,
    LoyaltyTier? loyaltyTier,
    int? totalPoints,
    CompanyInfo? companyInfo,
    String? cccd,
    List<String>? attachments,
    String? address,
    String? avatarUrl,
    String? referralCode,
    String? referredBy,
    String? erpnextCustomerId,
    DateTime? createdAt,
    DateTime? updatedAt,
    DateTime? lastLoginAt,
  }) {
    return User(
      userId: userId ?? this.userId,
      phoneNumber: phoneNumber ?? this.phoneNumber,
      fullName: fullName ?? this.fullName,
      email: email ?? this.email,
      role: role ?? this.role,
      status: status ?? this.status,
      loyaltyTier: loyaltyTier ?? this.loyaltyTier,
      totalPoints: totalPoints ?? this.totalPoints,
      companyInfo: companyInfo ?? this.companyInfo,
      cccd: cccd ?? this.cccd,
      attachments: attachments ?? this.attachments,
      address: address ?? this.address,
      avatarUrl: avatarUrl ?? this.avatarUrl,
      referralCode: referralCode ?? this.referralCode,
      referredBy: referredBy ?? this.referredBy,
      erpnextCustomerId: erpnextCustomerId ?? this.erpnextCustomerId,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
      lastLoginAt: lastLoginAt ?? this.lastLoginAt,
    );
  }

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

    return other is User &&
        other.userId == userId &&
        other.phoneNumber == phoneNumber &&
        other.fullName == fullName &&
        other.email == email &&
        other.role == role &&
        other.status == status &&
        other.loyaltyTier == loyaltyTier &&
        other.totalPoints == totalPoints &&
        other.cccd == cccd &&
        other.address == address &&
        other.avatarUrl == avatarUrl &&
        other.referralCode == referralCode &&
        other.referredBy == referredBy &&
        other.erpnextCustomerId == erpnextCustomerId;
  }

  @override
  int get hashCode {
    return Object.hash(
      userId,
      phoneNumber,
      fullName,
      email,
      role,
      status,
      loyaltyTier,
      totalPoints,
      cccd,
      address,
      avatarUrl,
      referralCode,
      referredBy,
      erpnextCustomerId,
    );
  }

  @override
  String toString() {
    return 'User(userId: $userId, phoneNumber: $phoneNumber, fullName: $fullName, '
        'role: $role, status: $status, loyaltyTier: $loyaltyTier, totalPoints: $totalPoints)';
  }
}
