import 'package:hl_lieferservice/domain/entity/tour_details.dart';

/// Lifecycle-States des `TourBloc`.
///
/// Bewusst eine sealed-Hierarchie: das UI kann via `switch` exhaustiv
/// alle Pfade abbilden und der Compiler meldet, wenn ein neuer Pfad
/// dazukommt.
sealed class TourState {
  const TourState();
}

/// App-Start, bevor irgendetwas geladen wurde.
class TourInitial extends TourState {
  const TourInitial();
}

/// Initial-Load läuft. Wird nur emittiert, wenn vorher kein Tour-State da
/// war — für Refresh siehe `TourLoaded.isRefreshing`.
class TourLoading extends TourState {
  const TourLoading();
}

/// Initial-Load ist gescheitert. Refresh-Fehler hingegen werden in
/// `TourLoaded.refreshError` getragen, damit die alte Tour sichtbar bleibt.
class TourLoadFailed extends TourState {
  const TourLoadFailed({required this.message});

  final String message;
}

/// Erfolgreich geladen — beinhaltet das volle Tour-Aggregat sowie
/// UI-relevante Zusatzflags rund um Reorder- und Refresh-Operationen.
class TourLoaded extends TourState {
  const TourLoaded({
    required this.details,
    this.isRefreshing = false,
    this.isPersistingReorder = false,
    this.refreshError,
    this.reorderError,
  });

  final TourDetails details;

  /// Hintergrund-Reload läuft (Pull-to-Refresh, Provider-Wakeup). UI darf
  /// die alte Daten weiter zeigen und nur einen schmalen Indikator
  /// einblenden.
  final bool isRefreshing;

  /// `PUT /tours/{id}/delivery-order` läuft. Sortier-Page nutzt das für
  /// den Bestätigungs-Button.
  final bool isPersistingReorder;

  /// Fehler eines Hintergrund-Reloads — bleibt für eine einzelne Snackbar
  /// hängen und wird beim nächsten Reload geleert.
  final String? refreshError;

  /// Fehler des letzten Reorder-Persist-Versuchs.
  final String? reorderError;

  TourLoaded copyWith({
    TourDetails? details,
    bool? isRefreshing,
    bool? isPersistingReorder,
    Object? refreshError = _sentinel,
    Object? reorderError = _sentinel,
  }) {
    return TourLoaded(
      details: details ?? this.details,
      isRefreshing: isRefreshing ?? this.isRefreshing,
      isPersistingReorder: isPersistingReorder ?? this.isPersistingReorder,
      refreshError: identical(refreshError, _sentinel)
          ? this.refreshError
          : refreshError as String?,
      reorderError: identical(reorderError, _sentinel)
          ? this.reorderError
          : reorderError as String?,
    );
  }

  /// Spezialfall: Initial-Load ist erfolgreich, aber das Backend hat dem
  /// angemeldeten Fahrer keine Tour für heute zugewiesen (kein ERP-Sync,
  /// Urlaub, …). UI kann darauf einen freundlichen Hinweis statt einer
  /// leeren Liste anzeigen.
  bool get isEmpty => details.deliveries.isEmpty;
}

const Object _sentinel = Object();

/// Erfolgs-Spezialform für „heute keine Tour zugewiesen". Wir behandeln das
/// als eigenständigen State (statt als `TourLoaded` mit leeren Listen),
/// damit das UI im Routing klar trennen kann zwischen „Tour vorhanden,
/// gerade keine Lieferungen offen" und „gar keine Tour für heute".
class TourEmpty extends TourState {
  const TourEmpty();
}
