enum PrinterType {
  wifi('Wifi'),
  bluetooth('Bluetooth');

  final String value;
  const PrinterType(this.value);

  bool get isWifi => this == PrinterType.wifi;
  bool get isBluetooth => this == PrinterType.bluetooth;

  factory PrinterType.fromValue(String value) {
    return values.firstWhere(
      (element) => element.value == value,
      orElse: () => PrinterType.wifi,
    );
  }
}

class PrinterModel {
  final int? id;
  final String code;
  final String name;
  final String ipAddress;
  final String size;
  final PrinterType type;
  final DateTime? createdAt;
  final DateTime? updatedAt;

  PrinterModel({
    this.id,
    required this.code,
    required this.name,
    required this.ipAddress,
    required this.size,
    required this.type,
    this.createdAt,
    this.updatedAt,
  });

  // Factory constructor to create PrinterModel from database map
  factory PrinterModel.fromMap(Map<String, dynamic> map) {
    return PrinterModel(
      id: map['id'] as int?,
      code: map['code'] as String,
      name: map['name'] as String,
      ipAddress: map['ip_address'] as String,
      size: map['size'] as String,
      type: PrinterType.fromValue(map['type'] as String),
      createdAt: map['created_at'] != null
          ? DateTime.parse(map['created_at'] as String)
          : null,
      updatedAt: map['updated_at'] != null
          ? DateTime.parse(map['updated_at'] as String)
          : null,
    );
  }

  // Convert to map for database insertion (excluding id, including timestamps)
  Map<String, dynamic> toMapForInsert() {
    final now = DateTime.now().toIso8601String();
    return {
      'code': code,
      'name': name,
      'ip_address': ipAddress,
      'size': size,
      'type': type.value,
      'created_at': now,
      'updated_at': now,
    };
  }

  // Convert to map for database update (excluding id and created_at)
  Map<String, dynamic> toMapForUpdate() {
    return {
      'code': code,
      'name': name,
      'ip_address': ipAddress,
      'size': size,
      'type': type.value,
      'updated_at': DateTime.now().toIso8601String(),
    };
  }

  // Convert to complete map (including id)
  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'code': code,
      'name': name,
      'ip_address': ipAddress,
      'size': size,
      'type': type.value,
      'created_at': createdAt?.toIso8601String(),
      'updated_at': updatedAt?.toIso8601String(),
    };
  }

  // Copy with method for creating modified instances
  PrinterModel copyWith({
    int? id,
    String? code,
    String? name,
    String? ipAddress,
    String? size,
    PrinterType? type,
    DateTime? createdAt,
    DateTime? updatedAt,
  }) {
    return PrinterModel(
      id: id ?? this.id,
      code: code ?? this.code,
      name: name ?? this.name,
      ipAddress: ipAddress ?? this.ipAddress,
      size: size ?? this.size,
      type: type ?? this.type,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

  // Equality and hashCode for comparing instances
  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is PrinterModel &&
        other.id == id &&
        other.code == code &&
        other.name == name &&
        other.ipAddress == ipAddress &&
        other.size == size &&
        other.type == type;
  }

  @override
  int get hashCode {
    return Object.hash(id, code, name, ipAddress, size, type);
  }

  // String representation for debugging
  @override
  String toString() {
    return 'PrinterModel(id: $id, code: $code, name: $name, ipAddress: $ipAddress, size: $size, type: ${type.value}, createdAt: $createdAt, updatedAt: $updatedAt)';
  }

  // Validation methods
  bool get isValid {
    return code.isNotEmpty &&
        name.isNotEmpty &&
        ipAddress.isNotEmpty &&
        size.isNotEmpty;
  }

  String? get validationError {
    if (code.isEmpty) return 'Printer code cannot be empty';
    if (name.isEmpty) return 'Printer name cannot be empty';
    if (ipAddress.isEmpty) return 'IP address cannot be empty';
    if (size.isEmpty) return 'Printer size cannot be empty';
    return null;
  }
}
