// lib/editor/persistence/sidecar_flush_observer.dart
//
// Phase 6 / §F.3 of the file-based storage plan (docs/plans/2026-06-24-file-
// based-storage.md): app-lifecycle flush hardening.
//
// The per-file SidecarRepository debounces writes by 800 ms. That window is the
// data-loss gap on a Windows tablet: if the OS suspends or closes the app
// before the timer fires, the last strokes never reach disk. This observer
// listens for the app leaving the foreground and DRAINS every open repo's
// pending write before the process can be frozen, so "never lose the last
// strokes on app close" holds even when the editor's own dispose() doesn't run.
//
// Registered once in BadNoteApp; it delegates to
// [SidecarRepositoryRegistry.flushAll], which awaits every repo's flush().

import 'package:flutter/widgets.dart';

import 'sidecar_repository.dart';

/// A [WidgetsBindingObserver] that flushes all open sidecar repositories when
/// the app leaves the foreground (`inactive`/`paused`/`detached`/`hidden`).
class SidecarFlushObserver with WidgetsBindingObserver {
  /// Whether the observer is currently registered with the binding.
  bool get isAttached => _attached;
  bool _attached = false;

  /// Register with [WidgetsBinding.instance] so lifecycle changes are observed.
  void attach() {
    if (_attached) return;
    WidgetsBinding.instance.addObserver(this);
    _attached = true;
  }

  /// Stop observing lifecycle changes.
  void detach() {
    if (!_attached) return;
    WidgetsBinding.instance.removeObserver(this);
    _attached = false;
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      // Any transition out of the foreground is a potential suspend/kill point:
      // drain pending sidecar writes now (the editors' own dispose() may never
      // run when the OS freezes the process).
      case AppLifecycleState.inactive:
      case AppLifecycleState.hidden:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        // Fire-and-forget at the framework boundary, but each write is atomic
        // and awaited inside flushAll, so a half-written sidecar is impossible.
        SidecarRepositoryRegistry.flushAll();
      case AppLifecycleState.resumed:
        break;
    }
  }
}
