use super::{FilterOption, FilterPlugin};
use regex::Regex;
use std::io::{BufRead, Read, Result, Write};

/// A filter that matches lines against a regular expression pattern.
///
/// Outputs only lines that match the given regex. Uses BufRead for line-by-line processing
/// and preserves original line endings.
///
/// # Fields
///
/// * `regex` - Compiled regex for matching.
#[derive(Debug, Clone)]
pub struct GrepFilter {
    regex: Regex,
}

/// Creates a new `GrepFilter` with the specified regex pattern.
///
/// Compiles the pattern using regex crate.
///
/// # Arguments
///
/// * `pattern` - The regular expression pattern (string) used to match lines.
///
/// # Returns
///
/// `Ok(Self)` on success.
///
/// # Errors
///
/// Returns `Err(io::Error::InvalidInput)` if pattern compilation fails (invalid regex).
///
/// # Examples
///
/// ```
/// # use keep::filter_plugin::GrepFilter;
/// let filter = GrepFilter::new("error|warn".to_string())?;
/// # Ok::<(), std::io::Error>(())
/// ```
impl GrepFilter {
    pub fn new(pattern: String) -> Result<Self> {
        let regex = Regex::new(&pattern)
            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
        Ok(Self { regex })
    }
}

/// Filters the input by writing only lines that match the regex pattern.
///
/// Reads lines from the input and writes matching lines to the output, preserving newlines.
/// Uses BufReader for efficient line iteration.
///
/// # Arguments
///
/// * `reader` - Mutable reference to the input data stream.
/// * `writer` - Mutable reference to the output writer where matching lines are sent.
///
/// # Returns
///
/// `Ok(())` on success.
///
/// # Errors
///
/// Propagates `io::Error` from BufRead lines() or writeln! (e.g., read/write failures, UTF-8 issues).
///
/// # Examples
///
/// ```
/// # use std::io::{Read, Write, Cursor};
/// # use keep::filter_plugin::{FilterPlugin, GrepFilter};
/// # let mut filter = GrepFilter::new("error".to_string())?;
/// let mut input: &mut dyn Read = &mut Cursor::new(b"error: something failed\nok: all good\n");
/// let mut output = Vec::new();
/// filter.filter(&mut input, &mut output)?;
/// # Ok::<(), std::io::Error>(())
/// ```
impl FilterPlugin for GrepFilter {
    fn filter(&mut self, reader: &mut dyn Read, writer: &mut dyn Write) -> Result<()> {
        let mut buf_reader = std::io::BufReader::new(reader);
        for line in buf_reader.by_ref().lines() {
            let line = line?;
            if self.regex.is_match(&line) {
                writeln!(writer, "{line}")?;
            }
        }
        Ok(())
    }

    /// Clones this filter into a new boxed instance.
    ///
    /// Creates a new GrepFilter with the same regex pattern.
    ///
    /// # Returns
    ///
    /// A new `Box<dyn FilterPlugin>` representing a clone of this filter.
    ///
    /// # Examples
    ///
    /// ```
    /// # use keep::filter_plugin::{FilterPlugin, GrepFilter};
    /// let filter = GrepFilter::new("test".to_string()).unwrap();
    /// let cloned = filter.clone_box();
    /// ```
    fn clone_box(&self) -> Box<dyn FilterPlugin> {
        Box::new(Self {
            regex: self.regex.clone(),
        })
    }

    /// Returns the configuration options for this filter.
    ///
    /// The only option is the required "pattern" for the regex.
    ///
    /// # Returns
    ///
    /// A vector containing one `FilterOption` for "pattern" (required, no default).
    ///
    /// # Examples
    ///
    /// ```
    /// # use keep::filter_plugin::{FilterPlugin, GrepFilter};
    /// let filter = GrepFilter::new("test".to_string()).unwrap();
    /// let opts = filter.options();
    /// assert_eq!(opts.len(), 1);
    /// assert!(opts[0].required);
    /// ```
    fn options(&self) -> Vec<FilterOption> {
        vec![FilterOption {
            name: "pattern".to_string(),
            default: None,
            required: true,
        }]
    }

    fn description(&self) -> &str {
        "Filter lines matching a regex pattern"
    }
}
