/// Domain Entity: User Session
///
/// Represents an active user session with device and authentication information.
library;

/// User Session Entity
///
/// Contains information about an active user session:
/// - Device details
/// - Authentication tokens
/// - Session timing
class UserSession {
  /// Unique session identifier
  final String sessionId;

  /// User ID associated with this session
  final String userId;

  /// Unique device identifier
  final String deviceId;

  /// Device type (ios, android, web)
  final String? deviceType;

  /// Device name
  final String? deviceName;

  /// IP address
  final String? ipAddress;

  /// User agent string
  final String? userAgent;

  /// Refresh token for renewing access
  final String? refreshToken;

  /// Session expiration timestamp
  final DateTime expiresAt;

  /// Session creation timestamp
  final DateTime createdAt;

  /// Last activity timestamp
  final DateTime? lastActivity;

  const UserSession({
    required this.sessionId,
    required this.userId,
    required this.deviceId,
    this.deviceType,
    this.deviceName,
    this.ipAddress,
    this.userAgent,
    this.refreshToken,
    required this.expiresAt,
    required this.createdAt,
    this.lastActivity,
  });

  /// Check if session is expired
  bool get isExpired => DateTime.now().isAfter(expiresAt);

  /// Check if session is expiring soon (within 1 hour)
  bool get isExpiringSoon {
    final hoursUntilExpiry = expiresAt.difference(DateTime.now()).inHours;
    return hoursUntilExpiry > 0 && hoursUntilExpiry <= 1;
  }

  /// Check if session is active
  bool get isActive => !isExpired;

  /// Get device display name
  String get deviceDisplayName => deviceName ?? deviceType ?? 'Unknown Device';

  /// Get time since last activity
  Duration? get timeSinceLastActivity {
    if (lastActivity == null) return null;
    return DateTime.now().difference(lastActivity!);
  }

  /// Copy with method for immutability
  UserSession copyWith({
    String? sessionId,
    String? userId,
    String? deviceId,
    String? deviceType,
    String? deviceName,
    String? ipAddress,
    String? userAgent,
    String? refreshToken,
    DateTime? expiresAt,
    DateTime? createdAt,
    DateTime? lastActivity,
  }) {
    return UserSession(
      sessionId: sessionId ?? this.sessionId,
      userId: userId ?? this.userId,
      deviceId: deviceId ?? this.deviceId,
      deviceType: deviceType ?? this.deviceType,
      deviceName: deviceName ?? this.deviceName,
      ipAddress: ipAddress ?? this.ipAddress,
      userAgent: userAgent ?? this.userAgent,
      refreshToken: refreshToken ?? this.refreshToken,
      expiresAt: expiresAt ?? this.expiresAt,
      createdAt: createdAt ?? this.createdAt,
      lastActivity: lastActivity ?? this.lastActivity,
    );
  }

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

    return other is UserSession &&
        other.sessionId == sessionId &&
        other.userId == userId &&
        other.deviceId == deviceId &&
        other.deviceType == deviceType &&
        other.deviceName == deviceName &&
        other.ipAddress == ipAddress &&
        other.refreshToken == refreshToken;
  }

  @override
  int get hashCode {
    return Object.hash(
      sessionId,
      userId,
      deviceId,
      deviceType,
      deviceName,
      ipAddress,
      refreshToken,
    );
  }

  @override
  String toString() {
    return 'UserSession(sessionId: $sessionId, userId: $userId, deviceId: $deviceId, '
        'deviceType: $deviceType, expiresAt: $expiresAt, isActive: $isActive)';
  }
}
