use super::{FilterOption, FilterPlugin};
use crate::common::PIPESIZE;
use crate::services::filter_service::register_filter_plugin;
use std::io::{BufRead, Read, Result, Write};

/// A filter that skips the first N bytes from the input stream.
pub struct SkipBytesFilter {
    remaining: usize,
}

impl SkipBytesFilter {
    /// Creates a new `SkipBytesFilter` that will skip the specified number of bytes.
    ///
    /// # Arguments
    ///
    /// * `count` - The number of bytes to skip from the beginning of the input.
    pub fn new(count: usize) -> Self {
        Self { remaining: count }
    }
}

impl FilterPlugin for SkipBytesFilter {
    /// Filters the input by skipping the first N bytes and writing the rest to the output.
    ///
    /// # Arguments
    ///
    /// * `reader` - Mutable reference to the input reader providing the data stream.
    /// * `writer` - Mutable reference to the output writer where filtered data is sent.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` on success, or an `io::Error` if reading or writing fails.
    fn filter(&mut self, reader: &mut dyn Read, writer: &mut dyn Write) -> Result<()> {
        // Skip bytes in chunks
        if self.remaining > 0 {
            let mut buffer = vec![0; PIPESIZE];
            while self.remaining > 0 {
                let to_read = std::cmp::min(self.remaining, PIPESIZE);
                let bytes_read = reader.read(&mut buffer[..to_read])?;
                if bytes_read == 0 {
                    break;
                }
                self.remaining -= bytes_read;
            }
        }

        // Copy the remaining data using io::copy for efficiency
        std::io::copy(reader, writer)?;
        Ok(())
    }

    /// Clones this filter into a new boxed instance.
    ///
    /// # Returns
    ///
    /// A new `Box<dyn FilterPlugin>` representing a clone of this filter.
    fn clone_box(&self) -> Box<dyn FilterPlugin> {
        Box::new(Self {
            remaining: self.remaining,
        })
    }

    /// Returns the configuration options for this filter.
    ///
    /// # Returns
    ///
    /// A vector of `FilterOption` describing the filter's configurable parameters.
    fn options(&self) -> Vec<FilterOption> {
        vec![FilterOption {
            name: "count".to_string(),
            default: None,
            required: true,
        }]
    }

    fn description(&self) -> &str {
        "Skip the first N bytes"
    }
}

/// A filter that skips the first N lines from the input stream.
pub struct SkipLinesFilter {
    remaining: usize,
}

impl SkipLinesFilter {
    /// Creates a new `SkipLinesFilter` that will skip the specified number of lines.
    ///
    /// # Arguments
    ///
    /// * `count` - The number of lines to skip from the beginning of the input.
    pub fn new(count: usize) -> Self {
        Self { remaining: count }
    }
}

impl FilterPlugin for SkipLinesFilter {
    /// Filters the input by skipping the first N lines and writing the rest to the output.
    ///
    /// # Arguments
    ///
    /// * `reader` - Mutable reference to the input reader providing the data stream.
    /// * `writer` - Mutable reference to the output writer where filtered data is sent.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` on success, or an `io::Error` if reading or writing fails.
    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.remaining > 0 {
                self.remaining -= 1;
            } else {
                writeln!(writer, "{line}")?;
            }
        }
        Ok(())
    }

    /// Clones this filter into a new boxed instance.
    ///
    /// # Returns
    ///
    /// A new `Box<dyn FilterPlugin>` representing a clone of this filter.
    fn clone_box(&self) -> Box<dyn FilterPlugin> {
        Box::new(Self {
            remaining: self.remaining,
        })
    }

    /// Returns the configuration options for this filter.
    ///
    /// # Returns
    ///
    /// A vector of `FilterOption` describing the filter's configurable parameters.
    fn options(&self) -> Vec<FilterOption> {
        vec![FilterOption {
            name: "count".to_string(),
            default: None,
            required: true,
        }]
    }

    fn description(&self) -> &str {
        "Skip the first N lines"
    }
}

// Register the plugin at module initialization time
#[ctor::ctor]
fn register_skip_filters() {
    register_filter_plugin("skip_bytes", || Box::new(SkipBytesFilter::new(0)))
        .expect("Failed to register skip_bytes filter");
    register_filter_plugin("skip_lines", || Box::new(SkipLinesFilter::new(0)))
        .expect("Failed to register skip_lines filter");
}
