use std::time::Duration;

use samod_core::{ConnectionId, DocumentId};

/// Trait for receiving structured observability events from the Repo.
///
/// Implement this trait and pass it to [`RepoBuilder::with_observer`] to
/// receive events about document lifecycle, peer connections, sync
/// processing, and storage operations.
pub trait RepoObserver: Send + Sync + 'static {
    fn observe(&self, event: &RepoEvent);
}

/// Events emitted by the Repo for observability.
#[non_exhaustive]
pub enum RepoEvent {
    /// A document actor was spawned.
    DocumentOpened {
        document_id: DocumentId,
    },
    /// A document actor was stopped.
    DocumentClosed {
        document_id: DocumentId,
    },

    /// A sync message was received and processed by a document actor.
    SyncMessageReceived {
        document_id: DocumentId,
        connection_id: ConnectionId,
        bytes: usize,
        /// How long it took to process this message
        duration: Duration,
        /// The time between the message being received and being processed
        queue_duration: Duration,
    },
    /// A sync message was generated by a document actor.
    SyncMessageGenerated {
        document_id: DocumentId,
        connection_id: ConnectionId,
        bytes: usize,
        /// How long it took to process this message
        duration: Duration,
    },

    /// A storage operation completed.
    StorageOperationCompleted {
        document_id: DocumentId,
        operation: StorageOperation,
        duration: Duration,
    },

    /// The hub finished processing one event.
    HubEventProcessed {
        /// How long it took to process this event
        duration: Duration,
        event_type: &'static str,
        connections: usize,
        documents: usize,
    },

    /// A new connection was created
    ConnectionEstablished {
        connection_id: ConnectionId,
    },

    ConnectionLost {
        connection_id: ConnectionId,
    },
    /// Number of sync messages pending during the Loading phase.
    DocumentPendingSyncMessages {
        document_id: DocumentId,
        count: usize,
    },
}

/// Types of storage operations for metrics.
pub enum StorageOperation {
    Load,
    LoadRange,
    Put,
    Delete,
}
