// Rolling ring of recent pen / arbiter events for diagnostic export.

class PenEventRecord {
  PenEventRecord({
    required this.at,
    required this.kind,
    required this.pointerId,
    this.pressure,
    this.tiltX,
    this.tiltY,
    this.barrel = false,
    this.eraser = false,
    this.inverted = false,
    this.decision,
    this.note,
  });

  final DateTime at;
  final String kind; // down|move|up|hw|arbiter
  final int pointerId;
  final double? pressure;
  final double? tiltX;
  final double? tiltY;
  final bool barrel;
  final bool eraser;
  final bool inverted;
  final String? decision; // draw|pan|reject
  final String? note;

  Map<String, Object?> toJson() => {
        'at': at.toIso8601String(),
        'kind': kind,
        'pointerId': pointerId,
        if (pressure != null) 'pressure': pressure,
        if (tiltX != null) 'tiltX': tiltX,
        if (tiltY != null) 'tiltY': tiltY,
        'barrel': barrel,
        'eraser': eraser,
        'inverted': inverted,
        if (decision != null) 'decision': decision,
        if (note != null) 'note': note,
      };
}

class PenEventRing {
  PenEventRing._();
  static final PenEventRing instance = PenEventRing._();

  static const int capacity = 2000;
  final List<PenEventRecord> _events = <PenEventRecord>[];

  void add(PenEventRecord event) {
    _events.add(event);
    if (_events.length > capacity) {
      _events.removeRange(0, _events.length - capacity);
    }
  }

  void recordPointer({
    required String kind,
    required int pointerId,
    required String deviceKind,
    double? pressure,
    String? decision,
    String? note,
  }) {
    add(PenEventRecord(
      at: DateTime.now(),
      kind: kind,
      pointerId: pointerId,
      pressure: pressure,
      decision: decision,
      note: note ?? deviceKind,
    ));
  }

  void recordHardware({
    required bool barrel,
    required bool eraser,
    required bool inverted,
    required double tiltX,
    required double tiltY,
  }) {
    add(PenEventRecord(
      at: DateTime.now(),
      kind: 'hw',
      pointerId: -1,
      barrel: barrel,
      eraser: eraser,
      inverted: inverted,
      tiltX: tiltX,
      tiltY: tiltY,
    ));
  }

  void recordArbiter({
    required int activeCount,
    required String deviceKind,
    required bool draw,
    required bool fingerDrawing,
  }) {
    add(PenEventRecord(
      at: DateTime.now(),
      kind: 'arbiter',
      pointerId: -1,
      decision: draw ? 'draw' : 'pan',
      note: 'count=$activeCount kind=$deviceKind finger=$fingerDrawing',
    ));
  }

  List<PenEventRecord> recent({Duration? window}) {
    if (window == null) return List.unmodifiable(_events);
    final cut = DateTime.now().subtract(window);
    return _events.where((e) => e.at.isAfter(cut)).toList(growable: false);
  }

  List<Map<String, Object?>> toJsonList({Duration? window}) =>
      recent(window: window).map((e) => e.toJson()).toList(growable: false);

  void clear() => _events.clear();
}
