/// Events für den [`TourBloc`].
///
/// Bewusst minimaler Scope für Phase C+D-2: Lese-Pfad, Reorder,
/// Car-Assign. Scan-, Hold-, Cancel-, Complete-, Discount- und
/// Notiz-Events kommen in C+D-3 / C+D-4 zurück.
sealed class TourEvent {
  const TourEvent();
}

/// Initial-Load der heutigen Tour des angemeldeten Fahrers.
/// Account-Filter sitzt im JWT — kein zusätzliches Argument nötig.
class LoadTour extends TourEvent {
  const LoadTour();
}

/// Pull-to-refresh / manueller Reload aus der Übersicht. Vorhandener
/// `TourLoaded`-State bleibt sichtbar, bis der neue Snapshot da ist;
/// `TourLoading` wird nur emittiert, wenn vorher kein State existierte.
class RefreshTour extends TourEvent {
  const RefreshTour();
}

/// Schreibt die Sortier-Reihenfolge aller Lieferungen einer Tour an das
/// Backend. Der Bloc fordert die UI nicht auf, die vollständige Reihenfolge
/// zu kennen — sie wird aus der Liste übergeben.
class ReorderDeliveries extends TourEvent {
  const ReorderDeliveries({required this.orderedDeliveryIds});

  final List<String> orderedDeliveryIds;
}

/// Weist einer Lieferung ein Fahrzeug zu — oder hebt die Zuweisung auf
/// (`carId == null`).
class AssignCarToDelivery extends TourEvent {
  const AssignCarToDelivery({required this.deliveryId, required this.carId});

  final String deliveryId;
  final String? carId;
}

/// Bulk-Variante: weist mehreren Lieferungen in einer atomaren Aktion das
/// gleiche Fahrzeug zu. Notwendig, weil flutter_bloc Events standardmäßig
/// **concurrent** verarbeitet — N parallel laufende `AssignCarToDelivery`-
/// Handler lesen alle den Initial-State und überschreiben sich gegenseitig
/// beim `emit`, sodass nur die letzte Zuweisung sichtbar bleibt. Der
/// Bulk-Handler verarbeitet die Liste sequenziell und emittiert genau
/// einen Zwischen-State am Ende.
///
/// Backend-seitig macht der Handler trotzdem N einzelne HTTP-Calls, weil
/// der `PATCH /deliveries/{id}/assigned-car`-Endpoint keine Liste kennt.
class AssignCarToDeliveries extends TourEvent {
  const AssignCarToDeliveries({
    required this.deliveryIds,
    required this.carId,
  });

  final List<String> deliveryIds;
  final String? carId;
}

/// Scan-Trigger aus der Loading-Phase. Der Bloc inkrementiert lokal
/// **optimistisch** die Scan-Quantität, ruft anschließend `POST /scans`
/// und rollt im `rejected`-Fall lokal zurück. `duplicate` ist still
/// (lokal schon hochgezählt, Server bestätigt nicht erneut).
///
/// `actorCarId` ist die UUID des aktuell gewählten Fahrzeugs — das
/// Backend nutzt das nur als Audit-Spur; an der Lieferung selbst
/// passiert dadurch nichts.
class ScanItem extends TourEvent {
  const ScanItem({
    required this.deliveryItemId,
    required this.actorCarId,
    this.manual = false,
  });

  final String deliveryItemId;
  final String actorCarId;

  /// `true` = manuelle Zeilen-Bestätigung (Fallback ohne Barcode): die
  /// **gesamte Restmenge** wird auf einmal als geladen verbucht und im
  /// Backend als `manual` protokolliert. `false` = regulärer Einzel-Scan (+1).
  final bool manual;
}

/// Umkehrung eines Scans (z. B. „falsch gescannt"). `reason` ist vom
/// Backend für `unscan` erforderlich.
class UnscanItem extends TourEvent {
  const UnscanItem({
    required this.deliveryItemId,
    required this.actorCarId,
    required this.reason,
  });

  final String deliveryItemId;
  final String actorCarId;
  final String reason;
}

/// Pausiert ein Item (`scan_status=held`). Reversibel über [UnholdItem].
/// `reason` Pflicht.
class HoldItem extends TourEvent {
  const HoldItem({
    required this.deliveryItemId,
    required this.actorCarId,
    required this.reason,
  });

  final String deliveryItemId;
  final String actorCarId;
  final String reason;
}

/// Setzt ein pausiertes Item zurück auf `in_progress`. Kein Reason
/// nötig — der Server löscht beim Unhold den `held_reason`.
class UnholdItem extends TourEvent {
  const UnholdItem({
    required this.deliveryItemId,
    required this.actorCarId,
  });

  final String deliveryItemId;
  final String actorCarId;
}

/// Entfernt ein Item aus der Lieferung (`scan_status=removed`).
/// `reason` Pflicht. Reversibel über [UnremoveItem] — die Historie
/// bleibt im Audit-Log vollständig erhalten.
class RemoveItem extends TourEvent {
  const RemoveItem({
    required this.deliveryItemId,
    required this.actorCarId,
    required this.reason,
    this.quantity,
    this.saveReasonAsNote = false,
  });

  final String deliveryItemId;
  final String actorCarId;
  final String reason;

  /// Mengen-Gutschrift: wie viele Stück gutgeschrieben werden. `null` =
  /// ganze Restmenge (= klassisches „ganze Zeile entfernen").
  final int? quantity;

  /// Wenn `true`, wird der `reason` nach erfolgreichem Entfernen zusätzlich
  /// als Lieferungs-Notiz gespeichert. Gesetzt aus dem Gutschrift-Flow
  /// (Step „Artikel & Gutschriften"); im Beladen-Flow `false`, dort wäre
  /// eine Notiz pro Abbuchung nur Rauschen.
  final bool saveReasonAsNote;
}

/// Stellt ein entferntes Item wieder her — geht nur, wenn der aktuelle
/// Status `removed` ist. Kein Reason nötig (Backend-Konvention wie bei
/// `unscan` und `unhold`). Audit-Log behält den ursprünglichen
/// `remove`-Eintrag und fügt einen neuen `unremove`-Eintrag hinzu.
class UnremoveItem extends TourEvent {
  const UnremoveItem({
    required this.deliveryItemId,
    required this.actorCarId,
    this.quantity,
  });

  final String deliveryItemId;
  final String actorCarId;

  /// Mengen-Gutschrift zurücknehmen: wie viele Stück wiederhergestellt
  /// werden. `null` = gesamte Gutschrift zurück.
  final int? quantity;
}

// ─── Delivery-Lifecycle ───────────────────────────────────────────────

/// Bricht eine Lieferung endgültig ab. `reason` ist Pflicht.
class CancelDelivery extends TourEvent {
  const CancelDelivery({required this.deliveryId, required this.reason});

  final String deliveryId;
  final String reason;
}

/// Pausiert eine Lieferung. `reason` ist Pflicht. Reversibel über
/// [ResumeDelivery].
class HoldDelivery extends TourEvent {
  const HoldDelivery({required this.deliveryId, required this.reason});

  final String deliveryId;
  final String reason;
}

/// Setzt eine pausierte Lieferung zurück auf `active`.
class ResumeDelivery extends TourEvent {
  const ResumeDelivery({required this.deliveryId});

  final String deliveryId;
}

/// Schließt eine Lieferung ab: lädt beide Unterschriften hoch, dokumentiert
/// die Bestätigungen des Kunden und setzt die Lieferung auf `completed`.
class CompleteDelivery extends TourEvent {
  const CompleteDelivery({
    required this.deliveryId,
    required this.customerSignaturePng,
    required this.driverSignaturePng,
    required this.receiptConfirmed,
    required this.notesAcknowledged,
    required this.acknowledgedNoteIds,
    this.paymentMethodId,
    this.actorCarId,
    this.paymentCollected = false,
  });

  final String deliveryId;
  final List<int> customerSignaturePng;
  final List<int> driverSignaturePng;
  final bool receiptConfirmed;
  final bool notesAcknowledged;
  final List<String> acknowledgedNoteIds;

  /// Vom Fahrer im Summary gewählte Zahlungsmethode (Override). `null` =
  /// die am Beleg hinterlegte Methode bleibt. Wird beim Abschluss persistiert.
  final String? paymentMethodId;
  final String? actorCarId;

  /// Fahrer hat das Vor-Ort-Inkasso (Bar/EC) des offenen Betrags bestätigt.
  /// `false`, wenn kein Inkasso anfiel (offen == 0 oder „Auf Rechnung").
  final bool paymentCollected;
}

/// Legt eine neue (Text- oder Bild-)Notiz an einer Lieferung an. Aktuell
/// wird nur der Text-Pfad von der UI getriggert; `imageAttachment` ist als
/// Storage-Key (z. B. Pre-Signed-URL-Key) gedacht und wartet auf die
/// zukünftige Foto-Upload-Phase.
/// Setzt/ändert die Betrags-Gutschrift einer Lieferung (Geld-Nachlass).
class SetDeliveryCredit extends TourEvent {
  const SetDeliveryCredit({
    required this.deliveryId,
    required this.amountCents,
    required this.reason,
    required this.actorCarId,
  });

  final String deliveryId;
  final int amountCents;
  final String reason;
  final String actorCarId;
}

/// Entfernt die Betrags-Gutschrift einer Lieferung.
class RemoveDeliveryCredit extends TourEvent {
  const RemoveDeliveryCredit({
    required this.deliveryId,
    required this.actorCarId,
  });

  final String deliveryId;
  final String actorCarId;
}

/// Setzt/ändert den Wert eines Service für eine Lieferung (Checkbox/Zahl).
class SetDeliveryServiceValue extends TourEvent {
  const SetDeliveryServiceValue({
    required this.deliveryId,
    required this.serviceId,
    required this.actorCarId,
    this.boolValue,
    this.numericValue,
  });

  final String deliveryId;
  final String serviceId;
  final String actorCarId;
  final bool? boolValue;
  final int? numericValue;
}

/// Entfernt den Service-Wert einer Lieferung (Service „nicht gesetzt").
class RemoveDeliveryServiceValue extends TourEvent {
  const RemoveDeliveryServiceValue({
    required this.deliveryId,
    required this.serviceId,
  });

  final String deliveryId;
  final String serviceId;
}

class AddDeliveryNote extends TourEvent {
  const AddDeliveryNote({
    required this.deliveryId,
    this.text,
    this.imageAttachment,
    this.creditDeliveryItemId,
  });

  final String deliveryId;
  final String? text;
  final String? imageAttachment;

  /// Optionaler Gutschrift-Bezug (DeliveryItem-Id). Gesetzt, wenn die Notiz
  /// einen Gutschrift-Grund dokumentiert — ermöglicht das Löschen beim
  /// Unremove.
  final String? creditDeliveryItemId;
}

/// Ändert Text/Bild einer bestehenden Notiz.
class UpdateDeliveryNote extends TourEvent {
  const UpdateDeliveryNote({
    required this.deliveryId,
    required this.noteId,
    this.text,
    this.imageAttachment,
  });

  final String deliveryId;
  final String noteId;
  final String? text;
  final String? imageAttachment;
}

/// Löscht eine Notiz.
class DeleteDeliveryNote extends TourEvent {
  const DeleteDeliveryNote({required this.deliveryId, required this.noteId});

  final String deliveryId;
  final String noteId;
}

/// Lädt ein Bild als Notiz hoch (geht über DOCUframe).
class UploadDeliveryNoteImage extends TourEvent {
  const UploadDeliveryNoteImage({
    required this.deliveryId,
    required this.filename,
    required this.mime,
    required this.bytes,
  });

  final String deliveryId;
  final String filename;
  final String mime;
  final List<int> bytes;
}
