//! List parsing and getter methods.

use super::super::errors::ParamsError;
use super::Params;

impl Params {
    /// Get list of strings from a parameter.
    ///
    /// Handles formats:
    /// - `"a,b,c"` - comma-separated
    /// - `"['a','b','c']"` - JSON-like array
    pub fn get_list(&self, key: &str) -> Result<Vec<String>, ParamsError> {
        let value = self.get(key)?;
        Ok(parse_list(value))
    }

    /// Get list with default if key not found.
    pub fn get_list_default(&self, key: &str, default: Vec<String>) -> Vec<String> {
        match self.find_param(key) {
            Some(p) if !p.value.is_empty() => parse_list(&p.value),
            _ => default,
        }
    }

    /// Get list with name normalization (lowercase, underscores for special chars).
    pub fn get_list_namefix(&self, key: &str) -> Result<Vec<String>, ParamsError> {
        let list = self.get_list(key)?;
        Ok(list.into_iter().map(|s| namefix(&s)).collect())
    }

    // === Numeric List Getters ===

    /// Get list of i32 values.
    pub fn get_list_int(&self, key: &str) -> Result<Vec<i32>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "i32")
    }

    /// Get list of i32 with default.
    pub fn get_list_int_default(
        &self,
        key: &str,
        default: Vec<i32>,
    ) -> Result<Vec<i32>, ParamsError> {
        match self.find_param(key) {
            Some(p) if !p.value.is_empty() => {
                let list = parse_list(&p.value);
                parse_numeric_list(&list, key, "i32")
            }
            _ => Ok(default),
        }
    }

    /// Get list of u8 values.
    pub fn get_list_u8(&self, key: &str) -> Result<Vec<u8>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "u8")
    }

    /// Get list of u16 values.
    pub fn get_list_u16(&self, key: &str) -> Result<Vec<u16>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "u16")
    }

    /// Get list of u32 values.
    pub fn get_list_u32(&self, key: &str) -> Result<Vec<u32>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "u32")
    }

    /// Get list of u64 values.
    pub fn get_list_u64(&self, key: &str) -> Result<Vec<u64>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "u64")
    }

    /// Get list of i8 values.
    pub fn get_list_i8(&self, key: &str) -> Result<Vec<i8>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "i8")
    }

    /// Get list of i16 values.
    pub fn get_list_i16(&self, key: &str) -> Result<Vec<i16>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "i16")
    }

    /// Get list of i64 values.
    pub fn get_list_i64(&self, key: &str) -> Result<Vec<i64>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "i64")
    }

    /// Get list of f32 values.
    pub fn get_list_f32(&self, key: &str) -> Result<Vec<f32>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "f32")
    }

    /// Get list of f64 values.
    pub fn get_list_f64(&self, key: &str) -> Result<Vec<f64>, ParamsError> {
        let list = self.get_list(key)?;
        parse_numeric_list(&list, key, "f64")
    }

    /// Get list of boolean values.
    pub fn get_list_bool(&self, key: &str) -> Result<Vec<bool>, ParamsError> {
        let list = self.get_list(key)?;
        list.iter()
            .map(|s| {
                let v = s.to_lowercase();
                match v.as_str() {
                    "" | "1" | "true" | "y" | "yes" => Ok(true),
                    "0" | "false" | "n" | "no" => Ok(false),
                    _ => Err(ParamsError::InvalidValue {
                        key: key.to_string(),
                        expected: "boolean".to_string(),
                        value: s.clone(),
                    }),
                }
            })
            .collect()
    }
}

/// Parse a value string into a list of strings.
fn parse_list(value: &str) -> Vec<String> {
    let trimmed = value.trim();

    // Handle empty
    if trimmed.is_empty() {
        return Vec::new();
    }

    // Handle JSON-like array format: ['a', 'b'] or ["a", "b"]
    if (trimmed.starts_with('[') && trimmed.ends_with(']'))
        || (trimmed.starts_with('(') && trimmed.ends_with(')'))
    {
        let inner = &trimmed[1..trimmed.len() - 1];
        return parse_comma_separated(inner);
    }

    // Regular comma-separated
    parse_comma_separated(trimmed)
}

/// Parse comma-separated values, handling quotes.
fn parse_comma_separated(text: &str) -> Vec<String> {
    let mut result = Vec::new();
    let mut current = String::new();
    let mut in_quote = false;
    let mut quote_char = ' ';

    for c in text.chars() {
        if !in_quote && (c == '\'' || c == '"') {
            in_quote = true;
            quote_char = c;
            continue;
        }

        if in_quote && c == quote_char {
            in_quote = false;
            continue;
        }

        if !in_quote && c == ',' {
            let trimmed = current.trim().to_string();
            if !trimmed.is_empty() {
                result.push(trimmed);
            }
            current.clear();
            continue;
        }

        current.push(c);
    }

    // Don't forget the last item
    let trimmed = current.trim().to_string();
    if !trimmed.is_empty() {
        result.push(trimmed);
    }

    result
}

/// Normalize a name: lowercase and replace special chars with underscore.
fn namefix(s: &str) -> String {
    s.chars()
        .map(|c| {
            if c.is_ascii_alphanumeric() {
                c.to_ascii_lowercase()
            } else {
                '_'
            }
        })
        .collect()
}

/// Generic function to parse a list of strings into numeric types.
fn parse_numeric_list<T: std::str::FromStr>(
    list: &[String],
    key: &str,
    type_name: &str,
) -> Result<Vec<T>, ParamsError> {
    list.iter()
        .map(|s| {
            s.trim()
                .parse::<T>()
                .map_err(|_| ParamsError::InvalidValue {
                    key: key.to_string(),
                    expected: format!("list of {}", type_name),
                    value: s.clone(),
                })
        })
        .collect()
}

#[cfg(test)]
mod tests {

    use super::super::parse as parse_params;

    #[test]
    fn test_get_list_comma_separated() {
        let params = parse_params("items:a,b,c").unwrap();
        let list = params.get_list("items").unwrap();
        assert_eq!(list, vec!["a", "b", "c"]);
    }

    #[test]
    fn test_get_list_json_array() {
        let params = parse_params("items:'[a, b, c]'").unwrap();
        let list = params.get_list("items").unwrap();
        assert_eq!(list, vec!["a", "b", "c"]);
    }

    #[test]
    fn test_get_list_quoted_items() {
        // Test with inner quoted items in a list value
        let params = parse_params("items:'hello world,foo bar'").unwrap();
        let list = params.get_list("items").unwrap();
        assert_eq!(list, vec!["hello world", "foo bar"]);
    }

    #[test]
    fn test_get_list_int() {
        let params = parse_params("nums:1,2,3,4,5").unwrap();
        let list = params.get_list_int("nums").unwrap();
        assert_eq!(list, vec![1, 2, 3, 4, 5]);
    }

    #[test]
    fn test_get_list_f64() {
        let params = parse_params("nums:1.5,2.5,3.5").unwrap();
        let list = params.get_list_f64("nums").unwrap();
        assert_eq!(list.len(), 3);
        assert!((list[0] - 1.5).abs() < 0.001);
    }

    #[test]
    fn test_get_list_bool() {
        let params = parse_params("flags:true,false,yes,no,1,0").unwrap();
        let list = params.get_list_bool("flags").unwrap();
        assert_eq!(list, vec![true, false, true, false, true, false]);
    }

    #[test]
    fn test_get_list_namefix() {
        let params = parse_params("names:'Hello World,Foo-Bar'").unwrap();
        let list = params.get_list_namefix("names").unwrap();
        assert_eq!(list, vec!["hello_world", "foo_bar"]);
    }

    #[test]
    fn test_get_list_default() {
        let params = parse_params("").unwrap();
        let default = vec!["a".to_string(), "b".to_string()];
        let list = params.get_list_default("missing", default.clone());
        assert_eq!(list, default);
    }

    #[test]
    fn test_empty_list() {
        // Empty list with explicit empty quotes
        let params = parse_params("items:''").unwrap();
        let list = params.get_list("items").unwrap();
        assert!(list.is_empty());
    }
}
