use crate::filter_plugin::{FilterChain, parse_filter_string};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::io::{Read, Result, Write};
use std::sync::Mutex;

type FilterConstructor = fn() -> Box<dyn crate::filter_plugin::FilterPlugin>;

/// Service for managing filter chains and plugin registration.
///
/// The `FilterService` provides functionality to parse filter strings, create filter chains,
/// and apply them to input/output streams. It integrates with the global filter plugin
/// registry to support dynamic loading of filter implementations like `head`, `tail`,
/// `grep`, and custom plugins.
///
/// # Usage
///
/// ```rust
/// use keep::services::FilterService;
/// let service = FilterService::new();
/// ```
pub struct FilterService;

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

impl FilterService {
    /// Creates a new `FilterService` instance.
    ///
    /// # Returns
    ///
    /// A new `FilterService`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use keep::services::FilterService;
    /// let service = FilterService::new();
    /// ```
    pub fn new() -> Self {
        Self
    }

    /// Creates a filter chain from a filter string specification.
    ///
    /// Parses the filter string using the filter parser and constructs a `FilterChain`
    /// with the appropriate plugins. Returns `None` if no filter string is provided.
    ///
    /// # Arguments
    ///
    /// * `filter_str` - Optional filter string, e.g., "head_lines(10),grep(pattern=error)".
    ///
    /// # Returns
    ///
    /// * `Result<Option<FilterChain>, io::Error>` - The parsed chain or an error if parsing fails.
    ///
    /// # Errors
    ///
    /// * `io::Error` - If the filter string is invalid or parsing fails.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let chain = service.create_filter_chain(Some("head_lines(10)"))?;
    /// assert!(chain.is_some());
    /// let empty = service.create_filter_chain(None)?;
    /// assert!(empty.is_none());
    /// ```
    pub fn create_filter_chain(&self, filter_str: Option<&str>) -> Result<Option<FilterChain>> {
        if let Some(filter_str) = filter_str {
            parse_filter_string(filter_str).map(Some)
        } else {
            Ok(None)
        }
    }

    /// Applies a filter chain to input data and writes to output.
    ///
    /// If a filter chain is provided, it processes the data through each filter in sequence.
    /// If no chain is provided, it copies the input directly to the output.
    ///
    /// # Type Parameters
    ///
    /// * `R` - Type implementing `Read` for the input source.
    /// * `W` - Type implementing `Write` for the output destination.
    ///
    /// # Arguments
    ///
    /// * `chain` - Mutable reference to an optional filter chain.
    /// * `reader` - Mutable reference to the input reader.
    /// * `writer` - Mutable reference to the output writer.
    ///
    /// # Returns
    ///
    /// * `Result<(), io::Error>` - Success or I/O error if filtering fails.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let mut chain = parse_filter_string("head_lines(5)")?;
    /// service.filter_data(&mut chain, &mut reader, &mut writer)?;
    /// ```
    pub fn filter_data<R: Read, W: Write>(
        &self,
        chain: &mut Option<FilterChain>,
        reader: &mut R,
        writer: &mut W,
    ) -> Result<()> {
        if let Some(chain) = chain {
            chain.filter(reader, writer)
        } else {
            // If no filter chain, just copy the input to output
            std::io::copy(reader, writer)?;
            Ok(())
        }
    }

    /// Convenience method to apply filters to in-memory data and return the result.
    ///
    /// Parses the filter string, applies the chain to the data via Cursor I/O,
    /// and collects output into a Vec<u8>. Ideal for non-streaming use cases.
    ///
    /// # Arguments
    ///
    /// * `data` - Input bytes to filter.
    /// * `filter_str` - Optional filter string specification.
    ///
    /// # Returns
    ///
    /// * `Ok(Vec<u8>)` - Filtered output bytes.
    /// * `Err(io::Error)` - If chain creation or filtering fails.
    ///
    /// # Errors
    ///
    /// Propagates parsing or I/O errors.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let filtered = service.process_with_filter(b"Hello\nWorld\n", Some("head_lines(1)"))?;
    /// assert_eq!(filtered, b"Hello\n");
    /// ```
    pub fn process_with_filter(&self, data: &[u8], filter_str: Option<&str>) -> Result<Vec<u8>> {
        let mut chain = self.create_filter_chain(filter_str)?;
        let mut reader = std::io::Cursor::new(data);
        let mut writer = Vec::new();

        if let Some(ref mut chain) = chain {
            chain.filter(&mut reader, &mut writer)?;
        } else {
            std::io::copy(&mut reader, &mut writer)?;
        }

        Ok(writer)
    }
}

/// Global thread-safe registry for filter plugins.
///
/// Lazily initialized Mutex<HashMap> mapping plugin names (e.g., "head_bytes") to their constructors.
/// Plugins self-register via ctors at module load time. Used by the parser to instantiate filters dynamically.
///
/// # Panics
///
/// Lock acquisition failures (rare) cause panics in accessors.
static FILTER_PLUGIN_REGISTRY: Lazy<Mutex<HashMap<String, FilterConstructor>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

/// Registers a filter plugin in the global registry.
///
/// Called by plugin modules at initialization to enable dynamic loading by name.
/// Supports plugin discovery and instantiation during filter chain parsing.
///
/// # Arguments
///
/// * `name` - Unique string identifier for the plugin (e.g., "head_lines").
/// * `constructor` - Zero-arg function returning a new boxed `FilterPlugin` instance.
///
/// # Panics
///
/// Panics if Mutex lock fails (unlikely).
///
/// # Examples
///
/// ```ignore
/// register_filter_plugin("custom_filter", || Box::new(CustomFilter::default()));
/// ```
pub fn register_filter_plugin(name: &str, constructor: FilterConstructor) -> anyhow::Result<()> {
    FILTER_PLUGIN_REGISTRY
        .lock()
        .map_err(|e| anyhow::anyhow!("plugin registry poisoned: {e}"))?
        .insert(name.to_string(), constructor);
    Ok(())
}

/// Retrieves a snapshot of all registered filter plugins.
///
/// Clones the registry for safe iteration. Useful for status reporting, validation, or UI display of available filters.
///
/// # Returns
///
/// HashMap clone with plugin names as keys and constructors as values.
///
/// # Panics
///
/// Panics if Mutex lock fails.
///
/// # Examples
///
/// ```
/// # use keep::services::filter_service::get_available_filter_plugins;
/// let plugins = get_available_filter_plugins();
/// // Plugins are registered at startup via ctors; specific names may vary by configuration.
/// ```
pub fn get_available_filter_plugins() -> anyhow::Result<HashMap<String, FilterConstructor>> {
    FILTER_PLUGIN_REGISTRY
        .lock()
        .map_err(|e| anyhow::anyhow!("plugin registry poisoned: {e}"))
        .map(|guard| guard.clone())
}
