using LiteDB;
namespace LehrerApp.Sync.Models;
// ── Events ────────────────────────────────────────────────────────────────────
/// Desktop-Event: Payload ist AES-256-GCM verschlüsselt.
public class SyncEvent
{
// LiteDB erkennt nur eine Property namens "Id" automatisch als Primärschlüssel.
// Ohne [BsonId] würde ein eigener, von EventId unabhängiger _id vergeben, wodurch
// EventQueue.Acknowledge()/_queue.Delete(EventId) niemals etwas löschen würde.
[BsonId]
public Guid EventId { get; init; } = Guid.NewGuid();
public string DeviceId { get; init; } = "";
public DeviceType DeviceType { get; init; }
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
public long SequenceNr { get; init; }
public string EntityType { get; init; } = "";
public string EntityId { get; init; } = "";
public string Operation { get; init; } = "";
/// Verschlüsselt (Desktop) oder Klartext (Companion/WebApp).
public string Payload { get; init; } = "";
///
/// ServerSeq, auf der die lokale Änderung aufbaut (null = Entität wurde hier noch nie
/// synchronisiert, z.B. Neuanlage). Wird von SyncEngine.PushAsync erst unmittelbar vor dem
/// Senden aus der lokalen Versionsverfolgung (EventQueue) gesetzt, nicht beim Einreihen —
/// so verwendet ein zweiter Push desselben Ereignisses (falls der erste abgelehnt wurde)
/// automatisch den inzwischen aktualisierten Stand.
///
public long? BasedOnServerSeq { get; set; }
}
/// WebApp/Companion-Event: Payload ist Klartext-JSON.
public class PlainSyncEvent
{
public Guid EventId { get; init; } = Guid.NewGuid();
public string DeviceId { get; init; } = "";
public DeviceType DeviceType { get; init; } = DeviceType.Companion;
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
public string EntityType { get; init; } = "";
public string EntityId { get; init; } = "";
public string Operation { get; init; } = "";
public string Payload { get; init; } = "";
}
// ── Sync API Responses ────────────────────────────────────────────────────────
public class PushResponse
{
public bool Success { get; init; }
public long ServerSequenceNr { get; init; }
public List ConflictingEventIds { get; init; } = [];
/// Je akzeptiertem Ereignis die tatsächlich vergebene ServerSeq — der Client braucht
/// das, um seine lokale Versionsverfolgung je Entität (EventQueue) auf den neuen Stand zu
/// bringen.
public Dictionary AssignedServerSeqs { get; init; } = [];
}
public class PullResponse
{
public List Events { get; init; } = [];
public long ServerSequenceNr { get; init; }
}
public class PlainPushResponse
{
public bool Success { get; init; }
public long ServerSequenceNr { get; init; }
public List RejectedEventIds { get; init; } = [];
}
// ── Snapshot Modelle ──────────────────────────────────────────────────────────
///
/// Upload-Request für Device-Pairing.
/// EncryptedPayload: LiteDB verschlüsselt mit Sync-Key.
/// EncryptedSyncKey: Sync-Key verschlüsselt mit PBKDF2(Code).
/// → Empfänger braucht nur den Code um beides zu entschlüsseln.
///
public class SnapshotUploadRequest
{
public string EncryptedPayload { get; init; } = "";
public string EncryptedSyncKey { get; init; } = "";
public DeviceType DeviceType { get; init; }
/// Gesetzt beim zweiten Upload-Schritt (Schlüssel nachreichen, siehe SnapshotService.
/// CreateAndUploadAsync) — muss dem im ersten Schritt vom Server vergebenen Code entsprechen,
/// damit derselbe Eintrag aktualisiert statt ein neuer (mit neuem Code) angelegt wird.
public string? Code { get; init; }
}
public class SnapshotUploadResponse
{
/// Format: WORT-ZZ-WORT, z.B. "TIGER-42-BLAU". 24h gültig, einmalig.
public string Code { get; init; } = "";
public DateTime ExpiresAt { get; init; }
}
public class SnapshotDownloadResponse
{
public string EncryptedPayload { get; init; } = "";
public string EncryptedSyncKey { get; init; } = "";
public DateTime CreatedAt { get; init; }
public DeviceType SourceDeviceType { get; init; }
}
// ── Status ────────────────────────────────────────────────────────────────────
public class SyncStatus
{
public SyncState State { get; set; } = SyncState.Idle;
public DateTime? LastSyncAt { get; set; }
public int PendingEvents { get; set; }
public int ConflictCount { get; set; }
public string? ErrorMessage { get; set; }
}
// ── Enums ─────────────────────────────────────────────────────────────────────
public enum DeviceType { Desktop, Companion }
public enum SyncState { Idle, Syncing, Error, Offline, IncompatibleVersion }