#![deny(
    clippy::panic,
    clippy::absolute_paths,
    clippy::print_stderr,
    clippy::print_stdout
)]

//! # PubMed Client
//!
//! A Rust client library for accessing PubMed and PMC (PubMed Central) APIs.
//! This crate provides easy-to-use interfaces for searching, fetching, and parsing
//! biomedical research articles.
//!
//! ## Features
//!
//! - **PubMed API Integration**: Search and fetch article metadata
//! - **PMC Full Text**: Retrieve and parse structured full-text articles
//! - **Markdown Export**: Convert PMC articles to well-formatted Markdown
//! - **Response Caching**: Reduce API quota usage with intelligent caching
//! - **Async Support**: Built on tokio for async/await support
//! - **Error Handling**: Comprehensive error types for robust error handling
//! - **Type Safety**: Strongly typed data structures for all API responses
//!
//! ## Quick Start
//!
//! ### Searching for Articles
//!
//! ```no_run
//! use pubmed_client::PubMedClient;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = PubMedClient::new();
//!
//!     // Search for articles with query builder
//!     let articles = client
//!         .search()
//!         .query("covid-19 treatment")
//!         .free_full_text_only()
//!         .published_after(2020)
//!         .limit(10)
//!         .search_and_fetch(&client)
//!         .await?;
//!
//!     for article in articles {
//!         println!("Title: {}", article.title);
//!         let author_names: Vec<&str> = article.authors.iter().map(|a| a.full_name.as_str()).collect();
//!         println!("Authors: {}", author_names.join(", "));
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Fetching Full Text from PMC
//!
//! ```no_run
//! use pubmed_client::PmcClient;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = PmcClient::new();
//!
//!     // Check if PMC full text is available
//!     if let Some(pmcid) = client.check_pmc_availability("33515491").await? {
//!         // Fetch structured full text
//!         let full_text = client.fetch_full_text(&pmcid).await?;
//!
//!         println!("Title: {}", full_text.title().unwrap_or("Untitled"));
//!         println!("Sections: {}", full_text.sections().len());
//!         println!("References: {}", full_text.references().len());
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Converting PMC Articles to Markdown
//!
//! ```no_run
//! use pubmed_client::{PmcClient, PmcMarkdownConverter, HeadingStyle, ReferenceStyle};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = PmcClient::new();
//!
//!     // Fetch and parse a PMC article
//!     if let Ok(full_text) = client.fetch_full_text("PMC1234567").await {
//!         // Create a markdown converter with custom configuration
//!         let converter = PmcMarkdownConverter::new()
//!             .with_include_metadata(true)
//!             .with_include_toc(true)
//!             .with_heading_style(HeadingStyle::ATX)
//!             .with_reference_style(ReferenceStyle::Numbered);
//!
//!         // Convert to markdown
//!         let markdown = converter.convert(&full_text);
//!         println!("{}", markdown);
//!
//!         // Or save to file
//!         std::fs::write("article.md", markdown)?;
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Downloading and Extracting PMC Articles as TAR files
//!
//! ```no_run
//! use pubmed_client::PmcClient;
//! use std::path::Path;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = PmcClient::new();
//!     let output_dir = Path::new("./extracted_articles");
//!
//!     // Download and extract a PMC article as tar.gz from the OA API
//!     let files = client.download_and_extract_tar("PMC7906746", output_dir).await?;
//!
//!     println!("Extracted {} files:", files.len());
//!     for file in files {
//!         println!("  - {}", file);
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Extracting Figures with Captions
//!
//! ```no_run
//! use pubmed_client::PmcClient;
//! use std::path::Path;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = PmcClient::new();
//!     let output_dir = Path::new("./extracted_articles");
//!
//!     // Extract figures and match them with captions from XML
//!     let figures = client.extract_figures_with_captions("PMC7906746", output_dir).await?;
//!
//!     for figure in figures {
//!         println!("Figure {}: {:?}", figure.figure.id, figure.figure.caption);
//!         println!("File: {}", figure.extracted_file_path);
//!         if let Some(dimensions) = figure.dimensions {
//!             println!("Dimensions: {}x{}", dimensions.0, dimensions.1);
//!         }
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Response Caching
//!
//! The library supports intelligent caching to reduce API quota usage and improve performance.
//!
//! ### Basic Caching
//!
//! ```no_run
//! use pubmed_client::{PmcClient, ClientConfig};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Enable default memory caching
//!     let config = ClientConfig::new().with_cache();
//!     let client = PmcClient::with_config(config);
//!
//!     // First fetch - hits the API
//!     let article1 = client.fetch_full_text("PMC7906746").await?;
//!
//!     // Second fetch - served from cache
//!     let article2 = client.fetch_full_text("PMC7906746").await?;
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Advanced Caching Options
//!
//! ```no_run
//! use pubmed_client::{PmcClient, ClientConfig};
//! use pubmed_client::cache::CacheConfig;
//! use std::time::Duration;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Memory cache with custom settings
//!     let cache_config = CacheConfig {
//!         max_capacity: 5000,
//!         time_to_live: Duration::from_secs(24 * 60 * 60), // 24 hours
//!         ..Default::default()
//!     };
//!
//!     let config = ClientConfig::new()
//!         .with_cache_config(cache_config);
//!     let client = PmcClient::with_config(config);
//!
//!     // Use the client normally - caching happens automatically
//!     let article = client.fetch_full_text("PMC7906746").await?;
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Hybrid Cache with Disk Persistence
//!
//! ```no_run
//! #[cfg(not(target_arch = "wasm32"))]
//! {
//! use pubmed_client::{PmcClient, ClientConfig};
//! use pubmed_client::cache::CacheConfig;
//! use std::time::Duration;
//! use std::path::PathBuf;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Memory cache configuration
//!     let cache_config = CacheConfig {
//!         max_capacity: 1000,
//!         time_to_live: Duration::from_secs(24 * 60 * 60),
//!         ..Default::default()
//!     };
//!
//!     let config = ClientConfig::new()
//!         .with_cache_config(cache_config);
//!     let client = PmcClient::with_config(config);
//!
//!     // Articles are cached in memory
//!     let article = client.fetch_full_text("PMC7906746").await?;
//!
//!     Ok(())
//! }
//! }
//! ```
//!
//! ### Cache Management
//!
//! ```no_run
//! use pubmed_client::{PmcClient, ClientConfig};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let config = ClientConfig::new().with_cache();
//!     let client = PmcClient::with_config(config);
//!
//!     // Fetch some articles
//!     client.fetch_full_text("PMC7906746").await?;
//!     client.fetch_full_text("PMC10618641").await?;
//!
//!     // Check cache statistics
//!     let count = client.cache_entry_count();
//!     println!("Cached items: {}", count);
//!
//!     // Clear the cache when needed
//!     client.clear_cache().await;
//!
//!     Ok(())
//! }
//! ```

pub mod cache;
pub mod config;
pub mod error;
pub mod pmc;
pub mod pubmed;
pub mod rate_limit;
pub(crate) mod request;
pub mod retry;
pub mod time;

// Common types from pubmed-parser are surfaced only at the crate root (below);
// the module itself is kept crate-internal to avoid duplicate public paths.
pub(crate) use pubmed_parser::common;

// Re-export main types for convenience
pub use common::{Affiliation, Author, PmcId, PubMedId};
pub use config::ClientConfig;
pub use error::{ParseError, PubMedError, Result};
pub use pmc::{
    Abstract, ArticleMeta, Back, Body, ExtractedFigure, Figure, FigureOptions, Front, FundingInfo,
    HeadingStyle, JournalMeta, License, MarkdownConfig, MetadataOptions, OaSubsetInfo, Permissions,
    PmcArticle, PmcClient, PmcMarkdownConverter, PmcTarClient, Reference, ReferenceStyle, Section,
    SupplementaryMaterial, Table, TitleGroup, parse_pmc_xml,
};
pub use pubmed::{
    AbstractSection, ArticleSummary, ArticleType, CitationMatch, CitationMatchStatus,
    CitationMatches, CitationQuery, Citations, DatabaseCount, DatabaseInfo, EPostResult,
    ExportFormat, FieldInfo, GlobalQueryResults, HistorySession, Language, LinkInfo, PmcLinks,
    PubMedArticle, PubMedClient, RelatedArticles, SearchQuery, SearchResult, SortOrder,
    SpellCheckResult, SpelledQuerySegment, export, parse_article_from_xml, validate_year,
};
pub use rate_limit::RateLimiter;
pub use time::{Duration, Instant, sleep};

/// Convenience client that combines both PubMed and PMC functionality
#[derive(Clone)]
pub struct Client {
    /// PubMed client for metadata
    pub pubmed: PubMedClient,
    /// PMC client for full text
    pub pmc: PmcClient,
}

impl Client {
    /// Create a new combined client with default configuration
    ///
    /// Uses default NCBI rate limiting (3 requests/second) and no API key.
    /// For production use, consider using `with_config()` to set an API key.
    ///
    /// # Example
    ///
    /// ```
    /// use pubmed_client::Client;
    ///
    /// let client = Client::new();
    /// ```
    pub fn new() -> Self {
        let config = ClientConfig::new();
        Self::with_config(config)
    }

    /// Create a new combined client with custom configuration
    ///
    /// Both PubMed and PMC clients will use the same configuration
    /// for consistent rate limiting and API key usage.
    ///
    /// # Arguments
    ///
    /// * `config` - Client configuration including rate limits, API key, etc.
    ///
    /// # Example
    ///
    /// ```
    /// use pubmed_client::{Client, ClientConfig};
    ///
    /// let config = ClientConfig::new()
    ///     .with_api_key("your_api_key_here")
    ///     .with_email("researcher@university.edu");
    ///
    /// let client = Client::with_config(config);
    /// ```
    pub fn with_config(config: ClientConfig) -> Self {
        Self {
            pubmed: PubMedClient::with_config(config.clone()),
            pmc: PmcClient::with_config(config),
        }
    }

    /// Create a new combined client with custom HTTP client
    ///
    /// # Arguments
    ///
    /// * `http_client` - Custom reqwest client with specific configuration
    ///
    /// # Example
    ///
    /// ```
    /// use pubmed_client::Client;
    /// use reqwest::ClientBuilder;
    /// use std::time::Duration;
    ///
    /// let http_client = ClientBuilder::new()
    ///     .timeout(Duration::from_secs(30))
    ///     .build()
    ///     .unwrap();
    ///
    /// let client = Client::with_http_client(http_client);
    /// ```
    pub fn with_http_client(http_client: reqwest::Client) -> Self {
        Self {
            pubmed: PubMedClient::with_client(http_client.clone()),
            pmc: PmcClient::with_client(http_client),
        }
    }

    /// Search for articles and attempt to fetch full text for each
    ///
    /// # Arguments
    ///
    /// * `query` - Search query string
    /// * `limit` - Maximum number of articles to process
    ///
    /// # Returns
    ///
    /// Returns a vector of tuples containing (`PubMedArticle`, `Option<PmcArticle>`)
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let results = client.search_with_full_text("covid-19", 5).await?;
    ///
    ///     for (article, full_text) in results {
    ///         println!("Article: {}", article.title);
    ///         if let Some(ft) = full_text {
    ///             println!("  Full text available with {} sections", ft.sections().len());
    ///         } else {
    ///             println!("  Full text not available");
    ///         }
    ///     }
    ///
    ///     Ok(())
    /// }
    /// ```
    pub async fn search_with_full_text(
        &self,
        query: &str,
        limit: usize,
    ) -> Result<Vec<(PubMedArticle, Option<PmcArticle>)>> {
        let articles = self.pubmed.search_and_fetch(query, limit, None).await?;
        let mut results = Vec::new();

        for article in articles {
            let full_text = match self.pmc.check_pmc_availability(&article.pmid).await? {
                Some(pmcid) => self.pmc.fetch_full_text(&pmcid).await.ok(),
                None => None,
            };
            results.push((article, full_text));
        }

        Ok(results)
    }

    /// Fetch multiple articles by PMIDs in a single batch request
    ///
    /// This is significantly more efficient than fetching articles one by one,
    /// as it sends fewer HTTP requests to the NCBI API.
    ///
    /// # Arguments
    ///
    /// * `pmids` - Slice of PubMed IDs as strings
    ///
    /// # Returns
    ///
    /// Returns a `Result<Vec<PubMedArticle>>` containing articles with metadata
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let articles = client.fetch_articles(&["31978945", "33515491"]).await?;
    ///     for article in &articles {
    ///         println!("{}: {}", article.pmid, article.title);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub async fn fetch_articles(&self, pmids: &[&str]) -> Result<Vec<PubMedArticle>> {
        self.pubmed.fetch_articles(pmids).await
    }

    /// Fetch lightweight article summaries by PMIDs using the ESummary API
    ///
    /// Returns basic metadata (title, authors, journal, dates, DOI) without
    /// abstracts, MeSH terms, or chemical lists. Faster than `fetch_articles()`
    /// when you only need bibliographic overview data.
    ///
    /// # Arguments
    ///
    /// * `pmids` - Slice of PubMed IDs as strings
    ///
    /// # Returns
    ///
    /// Returns a `Result<Vec<ArticleSummary>>` containing lightweight article metadata
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let summaries = client.fetch_summaries(&["31978945", "33515491"]).await?;
    ///     for summary in &summaries {
    ///         println!("{}: {}", summary.pmid, summary.title);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub async fn fetch_summaries(&self, pmids: &[&str]) -> Result<Vec<ArticleSummary>> {
        self.pubmed.fetch_summaries(pmids).await
    }

    /// Search and fetch lightweight summaries in a single operation
    ///
    /// Combines search and ESummary fetch. Use this when you only need basic
    /// metadata (title, authors, journal, dates) and want faster retrieval
    /// than `search_and_fetch()` which uses EFetch.
    ///
    /// # Arguments
    ///
    /// * `query` - Search query string
    /// * `limit` - Maximum number of articles
    ///
    /// # Returns
    ///
    /// Returns a `Result<Vec<ArticleSummary>>` containing lightweight article metadata
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let summaries = client.search_and_fetch_summaries("covid-19", 20).await?;
    ///     for summary in &summaries {
    ///         println!("{}: {}", summary.pmid, summary.title);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub async fn search_and_fetch_summaries(
        &self,
        query: &str,
        limit: usize,
    ) -> Result<Vec<ArticleSummary>> {
        self.pubmed
            .search_and_fetch_summaries(query, limit, None)
            .await
    }

    /// Get list of all available NCBI databases
    ///
    /// # Returns
    ///
    /// Returns a `Result<Vec<String>>` containing names of all available databases
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let databases = client.get_database_list().await?;
    ///     println!("Available databases: {:?}", databases);
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_database_list(&self) -> Result<Vec<String>> {
        self.pubmed.get_database_list().await
    }

    /// Get detailed information about a specific database
    ///
    /// # Arguments
    ///
    /// * `database` - Name of the database (e.g., "pubmed", "pmc", "books")
    ///
    /// # Returns
    ///
    /// Returns a `Result<DatabaseInfo>` containing detailed database information
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let db_info = client.get_database_info("pubmed").await?;
    ///     println!("Database: {}", db_info.name);
    ///     println!("Description: {}", db_info.description);
    ///     println!("Fields: {}", db_info.fields.len());
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_database_info(&self, database: &str) -> Result<DatabaseInfo> {
        self.pubmed.get_database_info(database).await
    }

    /// Get related articles for given PMIDs
    ///
    /// # Arguments
    ///
    /// * `pmids` - List of PubMed IDs to find related articles for
    ///
    /// # Returns
    ///
    /// Returns a `Result<RelatedArticles>` containing related article information
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let related = client.get_related_articles(&[31978945]).await?;
    ///     println!("Found {} related articles", related.related_pmids.len());
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_related_articles(&self, pmids: &[u32]) -> Result<RelatedArticles> {
        self.pubmed.get_related_articles(pmids).await
    }

    /// Get PMC links for given PMIDs (full-text availability)
    ///
    /// # Arguments
    ///
    /// * `pmids` - List of PubMed IDs to check for PMC availability
    ///
    /// # Returns
    ///
    /// Returns a `Result<PmcLinks>` containing PMC IDs with full text available
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let pmc_links = client.get_pmc_links(&[31978945]).await?;
    ///     println!("Found {} PMC articles", pmc_links.pmc_ids.len());
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_pmc_links(&self, pmids: &[u32]) -> Result<PmcLinks> {
        self.pubmed.get_pmc_links(pmids).await
    }

    /// Get citing articles for given PMIDs
    ///
    /// # Arguments
    ///
    /// * `pmids` - List of PubMed IDs to find citing articles for
    ///
    /// # Returns
    ///
    /// Returns a `Result<Citations>` containing citing article information
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let citations = client.get_citations(&[31978945]).await?;
    ///     println!("Found {} citing articles", citations.citing_pmids.len());
    ///     Ok(())
    /// }
    /// ```
    pub async fn get_citations(&self, pmids: &[u32]) -> Result<Citations> {
        self.pubmed.get_citations(pmids).await
    }

    /// Match citations to PMIDs using the ECitMatch API
    ///
    /// # Arguments
    ///
    /// * `citations` - List of citation queries to match
    ///
    /// # Returns
    ///
    /// Returns a `Result<CitationMatches>` containing match results
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::{Client, CitationQuery};
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let citations = vec![
    ///         CitationQuery::new("science", "1987", "235", "182", "palmenberg ac", "ref1"),
    ///     ];
    ///     let results = client.match_citations(&citations).await?;
    ///     println!("Found {} matches", results.found_count());
    ///     Ok(())
    /// }
    /// ```
    pub async fn match_citations(&self, citations: &[CitationQuery]) -> Result<CitationMatches> {
        self.pubmed.match_citations(citations).await
    }

    /// Query all NCBI databases for record counts
    ///
    /// # Arguments
    ///
    /// * `term` - Search query string
    ///
    /// # Returns
    ///
    /// Returns a `Result<GlobalQueryResults>` containing counts per database
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let results = client.global_query("asthma").await?;
    ///     for db in results.non_zero() {
    ///         println!("{}: {} records", db.menu_name, db.count);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub async fn global_query(&self, term: &str) -> Result<GlobalQueryResults> {
        self.pubmed.global_query(term).await
    }

    /// Upload a list of PMIDs to the NCBI History server using EPost
    ///
    /// # Arguments
    ///
    /// * `pmids` - Slice of PubMed IDs as strings
    ///
    /// # Returns
    ///
    /// Returns a `Result<EPostResult>` containing WebEnv and query_key
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let result = client.epost(&["31978945", "33515491"]).await?;
    ///     let session = result.history_session();
    ///     let articles = client.pubmed.fetch_from_history(&session, 0, 100).await?;
    ///     println!("Fetched {} articles", articles.len());
    ///     Ok(())
    /// }
    /// ```
    pub async fn epost(&self, pmids: &[&str]) -> Result<EPostResult> {
        self.pubmed.epost(pmids).await
    }

    /// Fetch all articles for a list of PMIDs using EPost and the History server
    ///
    /// Uploads the PMID list via EPost (HTTP POST), then fetches articles in
    /// paginated batches. Recommended for large PMID lists (hundreds or thousands).
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let articles = client.fetch_all_by_pmids(&["31978945", "33515491"]).await?;
    ///     for a in &articles {
    ///         println!("{}: {}", a.pmid, a.title);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub async fn fetch_all_by_pmids(&self, pmids: &[&str]) -> Result<Vec<PubMedArticle>> {
        self.pubmed.fetch_all_by_pmids(pmids).await
    }

    /// Check spelling of a search term using the ESpell API
    ///
    /// Provides spelling suggestions for terms within a single text query.
    /// Uses the PubMed database by default. For other databases, use
    /// `client.pubmed.spell_check_db(term, db)` directly.
    ///
    /// # Arguments
    ///
    /// * `term` - The search term to spell-check
    ///
    /// # Returns
    ///
    /// Returns a `Result<SpellCheckResult>` containing spelling suggestions
    ///
    /// # Example
    ///
    /// ```no_run
    /// use pubmed_client::Client;
    ///
    /// #[tokio::main]
    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
    ///     let client = Client::new();
    ///     let result = client.spell_check("asthmaa").await?;
    ///     println!("Corrected: {}", result.corrected_query);
    ///     Ok(())
    /// }
    /// ```
    pub async fn spell_check(&self, term: &str) -> Result<SpellCheckResult> {
        self.pubmed.spell_check(term).await
    }
}

impl Default for Client {
    fn default() -> Self {
        Self::new()
    }
}
