
enum TraktSyncJobType {
  scrobbleStart('scrobble_start'),
  scrobblePause('scrobble_pause'),
  scrobbleStop('scrobble_stop'),
  historyAdd('history_add'),
  historyRemove('history_remove');

  const TraktSyncJobType(this.wire);


  final String wire;

  bool get isHistory => this == historyAdd || this == historyRemove;

  static TraktSyncJobType fromWire(String wire) {
    return TraktSyncJobType.values.firstWhere(
      (e) => e.wire == wire,
      orElse: () => TraktSyncJobType.scrobbleStart,
    );
  }
}


class TraktSyncJob {
  final String id;
  final TraktSyncJobType type;
  final Map<String, dynamic> body;
  final int retryCount;
  final DateTime? nextRetryAt;
  final bool exhausted;

  const TraktSyncJob({
    required this.id,
    required this.type,
    required this.body,
    this.retryCount = 0,
    this.nextRetryAt,
    this.exhausted = false,
  });

  TraktSyncJob copyWith({
    int? retryCount,
    DateTime? nextRetryAt,
    bool clearNextRetryAt = false,
    bool? exhausted,
  }) {
    return TraktSyncJob(
      id: id,
      type: type,
      body: body,
      retryCount: retryCount ?? this.retryCount,
      nextRetryAt: clearNextRetryAt ? null : (nextRetryAt ?? this.nextRetryAt),
      exhausted: exhausted ?? this.exhausted,
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id,
    'type': type.wire,
    'body': body,
    'retryCount': retryCount,
    'nextRetryAt': nextRetryAt?.toIso8601String(),
    'exhausted': exhausted,
  };

  factory TraktSyncJob.fromJson(Map<String, dynamic> json) {
    return TraktSyncJob(
      id: json['id'] as String,
      type: TraktSyncJobType.fromWire(json['type'] as String? ?? ''),
      body: (json['body'] as Map?)?.cast<String, dynamic>() ?? const {},
      retryCount: (json['retryCount'] as num?)?.toInt() ?? 0,
      nextRetryAt: _parseDate(json['nextRetryAt']),
      exhausted: json['exhausted'] as bool? ?? false,
    );
  }

  static DateTime? _parseDate(Object? raw) {
    if (raw is! String || raw.isEmpty) return null;
    return DateTime.tryParse(raw);
  }
}
