//! Async repository trait defining standard CRUD operations.

use std::future::Future;

use uuid::Uuid;

use super::error::Result;

/// Async repository trait for model persistence.
///
/// Implementations are provided by the `postgres` and `iceberg` modules.
pub trait Repository<T: Send + Sync>: Send + Sync {
    /// Delete an entity by its primary key. Returns the number of rows removed.
    fn delete(&self, id: Uuid) -> impl Future<Output = Result<u64>> + Send;

    /// Insert a single entity, returning it with server-generated fields populated.
    fn insert(&self, entity: T) -> impl Future<Output = Result<T>> + Send;

    /// Insert multiple entities in a single batch operation.
    fn insert_batch(&self, entities: &[T]) -> impl Future<Output = Result<Vec<T>>> + Send;

    /// List entities matching the given filters.
    ///
    /// Filters are passed as key-value pairs where keys are column names.
    fn list(
        &self,
        filters: &[(&str, serde_json::Value)],
    ) -> impl Future<Output = Result<Vec<T>>> + Send;

    /// Read a single entity by its primary key.
    fn read(&self, id: Uuid) -> impl Future<Output = Result<Option<T>>> + Send;

    /// Update an existing entity. Returns an error if the entity does not exist.
    fn update(&self, entity: T) -> impl Future<Output = Result<T>> + Send;

    /// Insert or update an entity using the implementation's opinionated
    /// conflict target and merge columns.
    fn upsert(&self, entity: T) -> impl Future<Output = Result<T>> + Send;

    /// Insert or update multiple entities in a single batch operation.
    ///
    /// See [`Repository::upsert`] for the conflict target contract — each
    /// implementation picks its own.
    fn upsert_batch(&self, entities: &[T]) -> impl Future<Output = Result<Vec<T>>> + Send;
}
