// Allow patterns that clippy suggests replacing with unstable features
#![allow(clippy::collapsible_if)]
#![allow(clippy::manual_is_multiple_of)]

//! # JMESPath Extensions
//!
//! A comprehensive collection of 100+ extension functions for [JMESPath](https://jmespath.org/) queries.
//!
//! ## Non-Standard Extension Warning
//!
//! > **These functions are NOT part of the [JMESPath specification](https://jmespath.org/specification.html).**
//!
//! Queries using these extension functions will **NOT work** in other JMESPath
//! implementations (Python, JavaScript, Go, etc.). If you need portable queries,
//! use only the [26 standard JMESPath built-in functions](https://jmespath.org/specification.html#built-in-functions):
//!
//! > `abs`, `avg`, `ceil`, `contains`, `ends_with`, `floor`, `join`, `keys`,
//! > `length`, `map`, `max`, `max_by`, `merge`, `min`, `min_by`, `not_null`,
//! > `reverse`, `sort`, `sort_by`, `starts_with`, `sum`, `to_array`, `to_number`,
//! > `to_string`, `type`, `values`
//!
//! These extensions are useful when:
//! - You control both the query author and the runtime environment
//! - You need functionality beyond standard JMESPath
//! - Cross-implementation compatibility is not required
//!
//! ## Quick Start
//!
//! ```rust
//! # #[cfg(feature = "string")]
//! # fn main() {
//! use jmespath::{Runtime, Variable};
//! use jmespath_extensions::register_all;
//!
//! // Create a runtime and register all extension functions
//! let mut runtime = Runtime::new();
//! runtime.register_builtin_functions();
//! register_all(&mut runtime);
//!
//! // Use string functions
//! let expr = runtime.compile("upper(@)").unwrap();
//! let data = Variable::String("hello".to_string());
//! let result = expr.search(&data).unwrap();
//! assert_eq!(result.as_string().unwrap(), "HELLO");
//! # }
//! # #[cfg(not(feature = "string"))]
//! # fn main() {}
//! ```
//!
//! ## Working with JSON Data
//!
//! Most real-world usage involves querying JSON data:
//!
//! ```rust
//! # #[cfg(feature = "string")]
//! # fn main() {
//! use jmespath::{Runtime, Variable};
//! use jmespath_extensions::register_all;
//!
//! let mut runtime = Runtime::new();
//! runtime.register_builtin_functions();
//! register_all(&mut runtime);
//!
//! // Parse JSON data
//! let json = r#"{
//!     "users": [
//!         {"name": "alice", "email": "ALICE@EXAMPLE.COM"},
//!         {"name": "bob", "email": "BOB@EXAMPLE.COM"}
//!     ]
//! }"#;
//! let data = Variable::from_json(json).unwrap();
//!
//! // Query with extension functions
//! let expr = runtime.compile("users[*].{name: upper(name), email: lower(email)}").unwrap();
//! let result = expr.search(&data).unwrap();
//!
//! // Result: [{"name": "ALICE", "email": "alice@example.com"}, {"name": "BOB", "email": "bob@example.com"}]
//! # }
//! # #[cfg(not(feature = "string"))]
//! # fn main() {}
//! ```
//!
//! ## Feature Flags
//!
//! This crate uses feature flags to control which functions are included.
//! This allows you to minimize dependencies and binary size.
//!
//! | Feature | Dependencies | Description |
//! |---------|--------------|-------------|
//! | `full` (default) | all | All functions |
//! | `core` | none | String, array, object, math, type, utility, path |
//! | `string` | none | [String manipulation](string/index.html) |
//! | `array` | none | [Array operations](array/index.html) |
//! | `object` | none | [Object utilities](object/index.html) |
//! | `math` | none | [Mathematical operations](math/index.html) |
//! | `type` | none | [Type conversion and checking](type_conv/index.html) |
//! | `utility` | none | [Utility functions](utility/index.html) |
//! | `path` | none | [Path manipulation](path/index.html) |
//! | `validation` | none | [Validation functions](validation/index.html) |
//! | `hash` | md-5, sha1, sha2, crc32fast | [Hash functions](hash/index.html) |
//! | `encoding` | base64, hex | [Encoding functions](encoding/index.html) |
//! | `url` | url | [URL functions](url_fns/index.html) |
//! | `regex` | regex | [Regex functions](regex_fns/index.html) |
//! | `uuid` | uuid | UUID generation |
//! | `rand` | rand | [Random functions](random/index.html) |
//!
//! ### Using Specific Features
//!
//! ```toml
//! # Only include string and array functions (no external dependencies)
//! [dependencies]
//! jmespath_extensions = { version = "0.1", default-features = false, features = ["string", "array"] }
//!
//! # Include core functions plus regex
//! [dependencies]
//! jmespath_extensions = { version = "0.1", default-features = false, features = ["core", "regex"] }
//! ```
//!
//! ## Module Overview
//!
//! See each module's documentation for detailed function reference with examples:
//!
//! - [`string`] - String manipulation (`upper`, `lower`, `split`, `replace`, `camel_case`, etc.)
//! - [`mod@array`] - Array operations (`first`, `last`, `unique`, `chunk`, `zip`, `range`, etc.)
//! - [`object`] - Object utilities (`entries`, `pick`, `omit`, `deep_merge`, etc.)
//! - [`math`] - Math operations (`round`, `sqrt`, `pow`, `median`, `sin`, `cos`, etc.)
//! - [`type_conv`] - Type functions (`type_of`, `is_string`, `is_empty`, `to_number`, etc.)
//! - [`utility`] - Utilities (`now`, `default`, `if`, `coalesce`, `json_encode`, etc.)
//! - [`path`] - Path functions (`path_basename`, `path_dirname`, `path_ext`, `path_join`)
//! - [`validation`] - Validation (`is_email`, `is_url`, `is_uuid`, `is_ipv4`, `is_ipv6`)
//! - [`hash`] - Hashing (`md5`, `sha1`, `sha256`, `crc32`)
//! - [`encoding`] - Encoding (`base64_encode`, `base64_decode`, `hex_encode`, `hex_decode`)
//! - [`url_fns`] - URL functions (`url_encode`, `url_decode`, `url_parse`)
//! - [`regex_fns`] - Regex (`regex_match`, `regex_extract`, `regex_replace`)
//! - [`random`] - Random (`random`, `shuffle`, `sample`, `uuid`)
//!
//! ## Error Handling
//!
//! Extension functions follow JMESPath conventions:
//! - Type errors return an error (e.g., passing a number to `upper`)
//! - Invalid operations return null (e.g., `index_at` with out-of-bounds index)
//!
//! ```rust
//! use jmespath::{Runtime, Variable};
//! use jmespath_extensions::register_all;
//!
//! let mut runtime = Runtime::new();
//! runtime.register_builtin_functions();
//! register_all(&mut runtime);
//!
//! // Type error - upper expects a string
//! let expr = runtime.compile("upper(@)").unwrap();
//! let data = Variable::Number(serde_json::Number::from(42));
//! assert!(expr.search(&data).is_err());
//! ```
//!
//! ```rust
//! # use jmespath::{Runtime, Variable};
//! # use jmespath_extensions::register_all;
//! # let mut runtime = Runtime::new();
//! # runtime.register_builtin_functions();
//! # register_all(&mut runtime);
//! // Out of bounds - returns null (requires "array" feature)
//! # #[cfg(feature = "array")]
//! # {
//! let expr = runtime.compile("index_at(@, `10`)").unwrap();
//! let data = Variable::from_json("[1, 2, 3]").unwrap();
//! let result = expr.search(&data).unwrap();
//! assert!(result.is_null());
//! # }
//! ```

// Re-export common types
pub mod common;
pub use common::{
    ArgumentType, Context, ErrorReason, Function, JmespathError, Rcvar, Runtime, Signature,
    Variable,
};

// Core modules (no external dependencies)
#[cfg(feature = "string")]
pub mod string;

#[cfg(feature = "array")]
pub mod array;

#[cfg(feature = "object")]
pub mod object;

#[cfg(feature = "math")]
pub mod math;

#[cfg(feature = "type")]
pub mod type_conv;

#[cfg(feature = "utility")]
pub mod utility;

#[cfg(feature = "path")]
pub mod path;

#[cfg(feature = "validation")]
pub mod validation;

// Feature-gated modules with external dependencies
#[cfg(feature = "hash")]
pub mod hash;

#[cfg(feature = "encoding")]
pub mod encoding;

#[cfg(feature = "url")]
pub mod url_fns;

#[cfg(feature = "regex")]
pub mod regex_fns;

#[cfg(any(feature = "rand", feature = "uuid"))]
pub mod random;

/// Register all available extension functions with a JMESPath runtime.
///
/// This function registers all functions enabled by the current feature flags.
/// Call this after creating a new runtime and registering the built-in functions.
///
/// # Example
///
/// ```rust
/// use jmespath::Runtime;
/// use jmespath_extensions::register_all;
///
/// let mut runtime = Runtime::new();
/// runtime.register_builtin_functions();
/// register_all(&mut runtime);
///
/// // Now use any extension function
/// let expr = runtime.compile("upper(@)").unwrap();
/// ```
///
/// # Feature Flags
///
/// Only functions enabled by feature flags will be registered:
///
/// ```rust,ignore
/// // With default features (all functions)
/// register_all(&mut runtime);  // Registers 100+ functions
///
/// // With only "string" feature
/// register_all(&mut runtime);  // Registers only string functions
/// ```
#[allow(unused_variables)]
pub fn register_all(runtime: &mut Runtime) {
    #[cfg(feature = "string")]
    string::register(runtime);

    #[cfg(feature = "array")]
    array::register(runtime);

    #[cfg(feature = "object")]
    object::register(runtime);

    #[cfg(feature = "math")]
    math::register(runtime);

    #[cfg(feature = "type")]
    type_conv::register(runtime);

    #[cfg(feature = "utility")]
    utility::register(runtime);

    #[cfg(feature = "path")]
    path::register(runtime);

    #[cfg(feature = "validation")]
    validation::register(runtime);

    #[cfg(feature = "hash")]
    hash::register(runtime);

    #[cfg(feature = "encoding")]
    encoding::register(runtime);

    #[cfg(feature = "url")]
    url_fns::register(runtime);

    #[cfg(feature = "regex")]
    regex_fns::register(runtime);

    #[cfg(any(feature = "rand", feature = "uuid"))]
    random::register(runtime);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_register_all() {
        let mut runtime = Runtime::new();
        runtime.register_builtin_functions();
        register_all(&mut runtime);

        // Test a simple expression
        #[cfg(feature = "string")]
        {
            let expr = runtime.compile("upper(@)").unwrap();
            let data = Variable::String("hello".to_string());
            let result = expr.search(&data).unwrap();
            assert_eq!(result.as_string().unwrap(), "HELLO");
        }
    }
}
