pub use error::ExtractorError;

mod error;

#[cfg(feature = "openai")]
pub mod openai;
#[cfg(feature = "openai")]
pub use openai::OpenAIExtractor;

use std::future::Future;

use crate::Info;

/// Abstract extraction interface.
///
/// `items` is a list of `(key, source_texts)` pairs — `key` is a unique identifier
/// (e.g. domain, ID) and `source_texts` are the raw text pages to extract from.
/// Returns `(key, extracted_info)` pairs in the same order.
pub trait Extract<I: Info + Clone + Send + Sync + 'static>: Send + Sync + 'static {
    /// Required. Extract from multiple items, calling `on_batch` after each internal batch.
    fn extract(
        &self,
        items: &[(String, Vec<String>)],
        on_batch: &(dyn Fn(Vec<(String, I)>) + Send + Sync),
    ) -> impl Future<Output = Result<Vec<(String, I)>, ExtractorError>> + Send;

    /// Extract from multiple items without a progress callback.
    fn extract_all(
        &self,
        items: &[(String, Vec<String>)],
    ) -> impl Future<Output = Result<Vec<(String, I)>, ExtractorError>> + Send {
        async { self.extract(items, &|_| {}).await }
    }

    /// Extract from a single item.
    fn extract_one(
        &self,
        key: impl Into<String> + Send,
        texts: Vec<String>,
    ) -> impl Future<Output = Result<I, ExtractorError>> + Send {
        async move {
            self.extract(&[(key.into(), texts)], &|_| {})
                .await?
                .into_iter()
                .next()
                .map(|(_, info)| info)
                .ok_or(ExtractorError::NoResults)
        }
    }
}
