/*******************************************************************************
 *
 *    Copyright (c) 2025 - 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
//! # Fn Ops Trait Macro
//!
//! Generate extension traits and implementations for closure types
//!
//! This macro generates extension traits for closure types that implement
//! `Fn` or `FnMut`, providing `and_then` and `when` methods without requiring
//! explicit wrapping as `BoxTransformer`, `RcTransformer`, or `ArcTransformer`.
//!
//! # Parameters
//!
//! * `$fn_signature` - Closure signature (in parentheses, without constraints)
//!   Examples: `(Fn(T) -> R)`, `(FnMut(T) -> R)`
//! * `$trait_name` - Name of the extension trait (e.g., `FnTransformerOps`,
//!   `FnStatefulTransformerOps`)
//! * `$box_type` - Box wrapper type (e.g., `BoxTransformer`, `BoxStatefulTransformer`)
//! * `$chained_transformer_trait` - The name of the transformer trait that is
//!   chained after the execution of this transformer (e.g., Transformer,
//!   BiTransformer)
//! * `$conditional_type` - Conditional transformer type (e.g., BoxConditionalTransformer)
//!
//! # Implementation Notes
//!
//! The macro keeps the same composition shape for `Fn` and `FnMut` closures,
//! simplifying the generated `and_then` and `when` implementations while still
//! preserving transformer value-passing semantics.
//!
//! # Usage Examples
//!
//! ```ignore
//! // Generate extension trait for Fn(T) -> R
//! impl_fn_ops_trait!(
//!     (Fn(T) -> R),
//!     FnTransformerOps,
//!     BoxTransformer,
//!     Transformer,
//!     BoxConditionalTransformer
//! );
//!
//! // Generate extension trait for FnMut(T) -> R
//! impl_fn_ops_trait!(
//!     (FnMut(T) -> R),
//!     FnStatefulTransformerOps,
//!     BoxStatefulTransformer,
//!     StatefulTransformer,
//!     BoxConditionalStatefulTransformer
//! );
//! ```
//!

/// Generate extension traits and implementations for closure types
///
/// This macro generates an extension trait that provides composition methods
/// (`and_then`, `when`) for closures implementing the specified
/// closure trait, without requiring explicit wrapping.
///
/// # Unified Implementation Strategy
///
/// The macro uses a unified implementation approach for `Fn` and `FnMut`
/// transformer closures. This avoids duplicating the generated composition
/// methods while preserving the by-value input and output flow of transformers.
///
/// # Parameters
///
/// * `$fn_signature` - Closure signature (in parentheses, without constraints)
/// * `$trait_name` - Name of the extension trait
/// * `$box_type` - Box wrapper type
/// * `$chained_transformer_trait` - The name of the transformer trait that is
///   chained after the execution of this transformer (e.g., Transformer,
///   BiTransformer)
/// * `$conditional_type` - Conditional transformer type
///
/// # Generated Code
///
/// Generates a trait definition and a blanket implementation, containing:
/// - `and_then<S, F>` - Chain composition method
/// - `when<P>` - Conditional execution method
///
/// # Examples
///
/// ```ignore
/// // Fn(T) -> R version
/// impl_fn_ops_trait!(
///     (Fn(T) -> R),
///     FnTransformerOps,
///     BoxTransformer,
///     Transformer,
///     BoxConditionalTransformer
/// );
///
/// // FnMut(T) -> R version
/// impl_fn_ops_trait!(
///     (FnMut(T) -> R),
///     FnStatefulTransformerOps,
///     BoxStatefulTransformer,
///     StatefulTransformer,
///     BoxConditionalStatefulTransformer
/// );
/// ```
///
#[macro_export]
macro_rules! impl_fn_ops_trait {
    // Unified implementation - accepts closure signature (without constraints)
    (
        ($($fn_signature:tt)+),
        $trait_name:ident,
        $box_type:ident,
        $chained_transformer_trait:ident,
        $conditional_type:ident
    ) => {
        /// Extension trait for closures implementing the base transformer trait
        ///
        /// Provides composition methods (`and_then`, `when`) for closures
        /// and function pointers without requiring explicit wrapping.
        ///
        /// This trait is automatically implemented for all closures and function
        /// pointers that implement the base transformer trait.
        ///
        /// # Design Rationale
        ///
        /// While closures automatically implement the base transformer trait through blanket
        /// implementation, they don't have access to instance methods like `and_then`,
        /// and `when`. This extension trait provides those methods,
        /// returning the appropriate Box-based transformer type for maximum flexibility.
        ///
        /// # Examples
        ///
        /// ## Chain composition with and_then
        ///
        /// ```rust
        /// use qubit_function::{Transformer, FnTransformerOps};
        ///
        /// let double = |x: i32| x * 2;
        /// let to_string = |x: i32| x.to_string();
        ///
        /// let composed = double.and_then(to_string);
        /// assert_eq!(composed.apply(21), "42");
        /// ```
        ///
        /// ## Conditional transformation with when
        ///
        /// ```rust
        /// use qubit_function::{Transformer, FnTransformerOps};
        ///
        /// let double = |x: i32| x * 2;
        /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
        ///
        /// assert_eq!(conditional.apply(5), 10);
        /// assert_eq!(conditional.apply(-5), 5);
        /// ```
        ///
        pub trait $trait_name<T, R>: $($fn_signature)+ + Sized {
            /// Chain composition - applies self first, then after
            ///
            /// Creates a new transformer that applies this transformer first, then
            /// applies the after transformer to the result. Consumes self and returns
            /// a Box-based transformer.
            ///
            /// # Type Parameters
            ///
            /// * `S` - The output type of the after transformer
            /// * `F` - The type of the after transformer (must implement the transformer trait)
            ///
            /// # Parameters
            ///
            /// * `after` - The transformer to apply after self. **Note: This parameter
            ///   is passed by value and will transfer ownership.** If you need to
            ///   preserve the original transformer, clone it first (if it implements
            ///   `Clone`). Can be:
            ///   - A closure
            ///   - A function pointer
            ///   - A Box-based transformer
            ///   - An Rc-based transformer
            ///   - An Arc-based transformer
            ///   - Any type implementing the transformer trait
            ///
            /// # Returns
            ///
            /// A new Box-based transformer representing the composition
            ///
            /// # Examples
            ///
            /// ## Direct value passing (ownership transfer)
            ///
            /// ```rust
            /// use qubit_function::{BoxTransformer, FnTransformerOps, Transformer};
            ///
            /// let double = |x: i32| x * 2;
            /// let to_string = BoxTransformer::new(|x: i32| x.to_string());
            ///
            /// // to_string is moved here
            /// let composed = double.and_then(to_string);
            /// assert_eq!(composed.apply(21), "42");
            /// // to_string.apply(5); // Would not compile - moved
            /// ```
            ///
            /// ## Preserving original with clone
            ///
            /// ```rust
            /// use qubit_function::{BoxTransformer, FnTransformerOps, Transformer};
            ///
            /// let double = |x: i32| x * 2;
            /// let to_string = BoxTransformer::new(|x: i32| x.to_string());
            ///
            /// // Clone to preserve original
            /// let composed = double.and_then(to_string.clone());
            /// assert_eq!(composed.apply(21), "42");
            ///
            /// // Original still usable
            /// assert_eq!(to_string.apply(5), "5");
            /// ```
            #[allow(unused_mut)]
            #[inline]
            fn and_then<S, F>(mut self, mut after: F) -> $box_type<T, S>
            where
                Self: 'static,
                S: 'static,
                F: $chained_transformer_trait<R, S> + 'static,
                T: 'static,
                R: 'static,
            {
                $box_type::new(move |x| {
                  let r = self(x);
                  after.apply(r)
                })
            }

            /// Creates a conditional transformer
            ///
            /// Returns a transformer that only executes when a predicate is satisfied.
            /// You must call `or_else()` to provide an alternative transformer for when
            /// the condition is not satisfied.
            ///
            /// # Parameters
            ///
            /// * `predicate` - The condition to check. **Note: This parameter is passed
            ///   by value and will transfer ownership.** If you need to preserve the
            ///   original predicate, clone it first (if it implements `Clone`). Can be:
            ///   - A closure: `|x: &T| -> bool`
            ///   - A function pointer: `fn(&T) -> bool`
            ///   - A `BoxPredicate<T>`
            ///   - An `RcPredicate<T>`
            ///   - An `ArcPredicate<T>`
            ///   - Any type implementing `Predicate<T>`
            ///
            /// # Returns
            ///
            /// Returns the appropriate conditional transformer type
            ///
            /// # Examples
            ///
            /// ## Basic usage with or_else
            ///
            /// ```rust
            /// use qubit_function::{Transformer, FnTransformerOps};
            ///
            /// let double = |x: i32| x * 2;
            /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
            ///
            /// assert_eq!(conditional.apply(5), 10);
            /// assert_eq!(conditional.apply(-5), 5);
            /// ```
            ///
            /// ## Preserving predicate with clone
            ///
            /// ```rust
            /// use qubit_function::{BoxPredicate, FnTransformerOps, Predicate, Transformer};
            ///
            /// let double = |x: i32| x * 2;
            /// let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
            ///
            /// // Clone to preserve original predicate
            /// let conditional = double.when(is_positive.clone())
            ///     .or_else(|x: i32| -x);
            ///
            /// assert_eq!(conditional.apply(5), 10);
            ///
            /// // Original predicate still usable
            /// assert!(is_positive.test(&3));
            /// ```
            #[inline]
            fn when<P>(self, predicate: P) -> $conditional_type<T, R>
            where
                Self: 'static,
                P: Predicate<T> + 'static,
                T: 'static,
                R: 'static,
            {
                $box_type::new(self).when(predicate)
            }
        }

        /// Blanket implementation for all closures
        ///
        /// Automatically implements the extension trait for any type that
        /// implements the base transformer trait.
        ///
        impl<T, R, F> $trait_name<T, R> for F where F: $($fn_signature)+ {}
    };
}

pub(crate) use impl_fn_ops_trait;
