//! Autocompletion utilities for interactive prompts
//!
//! Provides helper classes for:
//! 1. **HistoryCompleter** - Remembers and suggests previously entered values
//! 2. **FilterCompleter** - Dynamically filters options
//! 3. **PatternCompleter** - Provides intelligent suggestions based on patterns

use std::collections::VecDeque;

/// History-based completion helper
/// Remembers previously entered values and suggests matches
#[derive(Clone, Debug)]
pub struct HistoryCompleter {
    history: VecDeque<String>,
    max_size: usize,
}

impl HistoryCompleter {
    /// Create a new history completer
    pub fn new(max_size: usize) -> Self {
        Self {
            history: VecDeque::new(),
            max_size,
        }
    }

    /// Add a value to history
    pub fn add(&mut self, value: String) {
        if !value.is_empty() {
            self.history.push_front(value);
            if self.history.len() > self.max_size {
                self.history.pop_back();
            }
        }
    }

    /// Get matching suggestions from history
    pub fn suggest(&self, partial: &str) -> Vec<String> {
        if partial.is_empty() {
            return self.history.iter().cloned().collect();
        }

        self.history
            .iter()
            .filter(|item| item.to_lowercase().contains(&partial.to_lowercase()))
            .cloned()
            .collect()
    }

    /// Get first completion suggestion
    pub fn complete(&self, partial: &str) -> Option<String> {
        if partial.is_empty() {
            return self.history.front().cloned();
        }

        self.history
            .iter()
            .find(|item| item.starts_with(partial))
            .cloned()
    }

    /// Get full history
    pub fn get_history(&self) -> Vec<String> {
        self.history.iter().cloned().collect()
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.history.clear();
    }
}

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

/// Filter-based completion helper
/// Dynamically filters available options
#[derive(Clone, Debug)]
pub struct FilterCompleter {
    options: Vec<String>,
}

impl FilterCompleter {
    /// Create a new filter completer
    pub fn new(options: Vec<String>) -> Self {
        Self { options }
    }

    /// Get filtered options matching the partial input
    pub fn filter(&self, partial: &str) -> Vec<String> {
        if partial.is_empty() {
            return self.options.clone();
        }

        self.options
            .iter()
            .filter(|opt| opt.to_lowercase().contains(&partial.to_lowercase()))
            .cloned()
            .collect()
    }

    /// Get first matching option
    pub fn complete(&self, partial: &str) -> Option<String> {
        if partial.is_empty() {
            return self.options.first().cloned();
        }

        self.options
            .iter()
            .find(|opt| opt.to_lowercase().starts_with(&partial.to_lowercase()))
            .cloned()
    }
}

/// Pattern types for intelligent completion
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub enum PatternType {
    /// Email pattern (suggests @domain)
    Email,
    /// URL pattern (suggests http://, https://)
    Url,
    /// File path pattern (suggests /, ./, ../)
    FilePath,
    /// IPv4 address pattern (suggests octets)
    IPv4,
    /// Port number pattern (suggests :)
    Port,
}

/// Pattern-based completion helper
/// Provides intelligent suggestions based on input patterns
#[derive(Clone, Debug)]
pub struct PatternCompleter {
    pattern: PatternType,
    suggestions: Vec<String>,
}

impl PatternCompleter {
    /// Create a new pattern completer
    pub fn new(pattern: PatternType) -> Self {
        let suggestions = match pattern {
            PatternType::Email => vec![
                "@gmail.com".to_string(),
                "@outlook.com".to_string(),
                "@example.com".to_string(),
                "@company.com".to_string(),
            ],
            PatternType::Url => vec![
                "https://".to_string(),
                "http://".to_string(),
                "ftp://".to_string(),
                "ssh://".to_string(),
            ],
            PatternType::FilePath => vec![
                "./".to_string(),
                "../".to_string(),
                "/".to_string(),
                "~/".to_string(),
            ],
            PatternType::IPv4 => vec![
                "192.168.".to_string(),
                "10.0.".to_string(),
                "172.16.".to_string(),
                "127.0.".to_string(),
            ],
            PatternType::Port => vec![
                ":8080".to_string(),
                ":3000".to_string(),
                ":5432".to_string(),
                ":80".to_string(),
                ":443".to_string(),
            ],
        };

        Self {
            pattern,
            suggestions,
        }
    }

    /// Add custom suggestion
    pub fn add_suggestion(&mut self, suggestion: String) {
        if !self.suggestions.contains(&suggestion) {
            self.suggestions.push(suggestion);
        }
    }

    /// Get suggestions matching the pattern
    pub fn suggest(&self, partial: &str) -> Vec<String> {
        self.suggestions
            .iter()
            .filter(|s| s.starts_with(partial) || partial.is_empty())
            .cloned()
            .collect()
    }

    /// Get first matching suggestion
    pub fn complete(&self, partial: &str) -> Option<String> {
        self.suggestions
            .iter()
            .find(|s| s.starts_with(partial))
            .cloned()
            .or_else(|| {
                // Smart completion based on pattern type
                match self.pattern {
                    PatternType::Email if !partial.contains('@') && !partial.is_empty() => {
                        Some("@example.com".to_string())
                    }
                    PatternType::Url if !partial.starts_with("http") && partial.is_empty() => {
                        Some("https://".to_string())
                    }
                    PatternType::Port if !partial.contains(':') && !partial.is_empty() => {
                        Some(":8080".to_string())
                    }
                    _ => None,
                }
            })
    }
}

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

    #[test]
    fn test_history_completer() {
        let mut completer = HistoryCompleter::new(3);
        completer.add("apple".to_string());
        completer.add("application".to_string());

        assert_eq!(completer.get_history().len(), 2);
        assert_eq!(completer.get_history()[0], "application");
    }

    #[test]
    fn test_history_max_size() {
        let mut completer = HistoryCompleter::new(2);
        completer.add("first".to_string());
        completer.add("second".to_string());
        completer.add("third".to_string());

        assert_eq!(completer.get_history().len(), 2);
    }

    #[test]
    fn test_filter_completer() {
        let options = vec![
            "apple".to_string(),
            "application".to_string(),
            "banana".to_string(),
        ];
        let completer = FilterCompleter::new(options);

        let filtered = completer.filter("app");
        assert_eq!(filtered.len(), 2);
        assert!(filtered.iter().any(|s| s == "apple"));
    }

    #[test]
    fn test_pattern_completer_email() {
        let mut completer = PatternCompleter::new(PatternType::Email);
        completer.add_suggestion("@mydomain.com".to_string());

        let suggestions = completer.suggest("@");
        assert!(!suggestions.is_empty());
        assert!(suggestions.iter().any(|s| s.contains("mydomain")));
    }

    #[test]
    fn test_pattern_completer_smart() {
        let completer = PatternCompleter::new(PatternType::Email);

        // Smart completion adds @example.com when there's no @
        let completion = completer.complete("user");
        assert_eq!(completion, Some("@example.com".to_string()));
    }
}
