abstract class DeviceFunction<T> {
  final String deviceId;
  final String deviceName;
  final String code;
  final String operationName;
  final String icon;
  final double? step;
  final String? unit;
  final double? max;
  final double? min;

  DeviceFunction({
    required this.deviceId,
    required this.deviceName,
    required this.code,
    required this.operationName,
    required this.icon,
    this.step,
    this.unit,
    this.max,
    this.min,
  });
}

class DeviceFunctionData {
  final String entityId;
  final String actionExecutor;
  final String functionCode;
  final String operationName;
  final dynamic value;
  final String? condition;
  final String? valueDescription;
  final double? step;
  final String? unit;
  final double? max;
  final double? min;

  DeviceFunctionData({
    required this.entityId,
    this.actionExecutor = 'device_issue',
    required this.functionCode,
    required this.operationName,
    required this.value,
    this.condition,
    this.valueDescription,
    this.step,
    this.unit,
    this.max,
    this.min,
  });

  Map<String, dynamic> toJson() {
    return {
      'entityId': entityId,
      'actionExecutor': actionExecutor,
      'function': functionCode,
      'operationName': operationName,
      'value': value,
      if (condition != null) 'condition': condition,
      if (valueDescription != null) 'valueDescription': valueDescription,
      if (step != null) 'step': step,
      if (unit != null) 'unit': unit,
      if (max != null) 'max': max,
      if (min != null) 'min': min,
    };
  }

  factory DeviceFunctionData.fromJson(Map<String, dynamic> json) {
    return DeviceFunctionData(
      entityId: json['entityId'],
      actionExecutor: json['actionExecutor'] ?? 'function',
      functionCode: json['function'],
      operationName: json['operationName'],
      value: json['value'],
      condition: json['condition'],
      valueDescription: json['valueDescription'],
      step: json['step']?.toDouble(),
      unit: json['unit'],
      max: json['max']?.toDouble(),
      min: json['min']?.toDouble(),
    );
  }

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

    return other is DeviceFunctionData &&
        other.entityId == entityId &&
        other.actionExecutor == actionExecutor &&
        other.functionCode == functionCode &&
        other.operationName == operationName &&
        other.value == value &&
        other.condition == condition &&
        other.valueDescription == valueDescription &&
        other.step == step &&
        other.unit == unit &&
        other.max == max &&
        other.min == min;
  }

  @override
  int get hashCode {
    return entityId.hashCode ^
        actionExecutor.hashCode ^
        functionCode.hashCode ^
        operationName.hashCode ^
        value.hashCode ^
        condition.hashCode ^
        valueDescription.hashCode ^
        step.hashCode ^
        unit.hashCode ^
        max.hashCode ^
        min.hashCode;
  }

  DeviceFunctionData copyWith({
    String? entityId,
    String? functionCode,
    String? operationName,
    String? condition,
    dynamic value,
    double? step,
    String? unit,
    double? max,
    double? min,
  }) {
    return DeviceFunctionData(
      entityId: entityId ?? this.entityId,
      functionCode: functionCode ?? this.functionCode,
      operationName: operationName ?? this.operationName,
      condition: condition ?? this.condition,
      value: value ?? this.value,
      step: step ?? this.step,
      unit: unit ?? this.unit,
      max: max ?? this.max,
      min: min ?? this.min,
    );
  }
}
