/// Domain Entity: Audit Log
///
/// Represents an audit trail entry for system activities.
library;

/// Audit Log Entity
///
/// Contains information about a system action:
/// - User and action details
/// - Entity affected
/// - Change tracking
/// - Session information
class AuditLog {
  /// Unique log identifier
  final String logId;

  /// User ID who performed the action
  final String? userId;

  /// Action performed (create, update, delete, login, etc.)
  final String action;

  /// Entity type affected (user, order, product, etc.)
  final String? entityType;

  /// Entity ID affected
  final String? entityId;

  /// Old value (before change)
  final Map<String, dynamic>? oldValue;

  /// New value (after change)
  final Map<String, dynamic>? newValue;

  /// IP address of the user
  final String? ipAddress;

  /// User agent string
  final String? userAgent;

  /// Timestamp of the action
  final DateTime timestamp;

  const AuditLog({
    required this.logId,
    this.userId,
    required this.action,
    this.entityType,
    this.entityId,
    this.oldValue,
    this.newValue,
    this.ipAddress,
    this.userAgent,
    required this.timestamp,
  });

  /// Check if log has old value
  bool get hasOldValue => oldValue != null && oldValue!.isNotEmpty;

  /// Check if log has new value
  bool get hasNewValue => newValue != null && newValue!.isNotEmpty;

  /// Check if action is create
  bool get isCreate => action.toLowerCase() == 'create';

  /// Check if action is update
  bool get isUpdate => action.toLowerCase() == 'update';

  /// Check if action is delete
  bool get isDelete => action.toLowerCase() == 'delete';

  /// Check if action is login
  bool get isLogin => action.toLowerCase() == 'login';

  /// Check if action is logout
  bool get isLogout => action.toLowerCase() == 'logout';

  /// Get changed fields
  List<String> get changedFields {
    if (!hasOldValue || !hasNewValue) return [];

    final changed = <String>[];
    for (final key in newValue!.keys) {
      if (oldValue!.containsKey(key) && oldValue![key] != newValue![key]) {
        changed.add(key);
      }
    }
    return changed;
  }

  /// Get time since action
  Duration get timeSinceAction {
    return DateTime.now().difference(timestamp);
  }

  /// Copy with method for immutability
  AuditLog copyWith({
    String? logId,
    String? userId,
    String? action,
    String? entityType,
    String? entityId,
    Map<String, dynamic>? oldValue,
    Map<String, dynamic>? newValue,
    String? ipAddress,
    String? userAgent,
    DateTime? timestamp,
  }) {
    return AuditLog(
      logId: logId ?? this.logId,
      userId: userId ?? this.userId,
      action: action ?? this.action,
      entityType: entityType ?? this.entityType,
      entityId: entityId ?? this.entityId,
      oldValue: oldValue ?? this.oldValue,
      newValue: newValue ?? this.newValue,
      ipAddress: ipAddress ?? this.ipAddress,
      userAgent: userAgent ?? this.userAgent,
      timestamp: timestamp ?? this.timestamp,
    );
  }

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

    return other is AuditLog &&
        other.logId == logId &&
        other.userId == userId &&
        other.action == action &&
        other.entityType == entityType &&
        other.entityId == entityId;
  }

  @override
  int get hashCode {
    return Object.hash(logId, userId, action, entityType, entityId);
  }

  @override
  String toString() {
    return 'AuditLog(logId: $logId, userId: $userId, action: $action, '
        'entityType: $entityType, entityId: $entityId, timestamp: $timestamp)';
  }
}
