//! Utility functions for Rustelo framework

use std::path::{Path, PathBuf};

use crate::error::{Result, RusteloError};

/// File system utilities
pub mod fs {
    use super::*;

    /// Ensure a directory exists, creating it if necessary
    pub fn ensure_dir<P: AsRef<Path>>(path: P) -> Result<()> {
        let path = path.as_ref();
        if !path.exists() {
            std::fs::create_dir_all(path).map_err(RusteloError::Io)?;
        }
        Ok(())
    }

    /// Copy a file, creating parent directories as needed
    pub fn copy_with_dirs<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
        let to = to.as_ref();
        if let Some(parent) = to.parent() {
            ensure_dir(parent)?;
        }

        std::fs::copy(from, to).map_err(RusteloError::Io)?;

        Ok(())
    }

    /// Find files matching a glob pattern
    pub fn find_files<P: AsRef<Path>>(base: P, pattern: &str) -> Result<Vec<PathBuf>> {
        use walkdir::WalkDir;

        let base = base.as_ref();
        let mut files = Vec::new();

        for entry in WalkDir::new(base) {
            let entry =
                entry.map_err(|e| RusteloError::generic(format!("Walk directory error: {}", e)))?;
            let path = entry.path();

            if path.is_file() {
                if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
                    if glob_match(pattern, name) {
                        files.push(path.to_path_buf());
                    }
                }
            }
        }

        Ok(files)
    }

    /// Simple glob matching (supports * wildcards)
    fn glob_match(pattern: &str, name: &str) -> bool {
        if pattern == "*" {
            return true;
        }

        if pattern.contains('*') {
            let parts: Vec<&str> = pattern.split('*').collect();
            if parts.len() == 2 {
                let prefix = parts[0];
                let suffix = parts[1];
                return name.starts_with(prefix) && name.ends_with(suffix);
            }
        }

        pattern == name
    }
}

/// String utilities
pub mod string {

    /// Convert a string to kebab-case
    pub fn to_kebab_case(input: &str) -> String {
        let mut result = String::new();
        let mut prev_char_was_uppercase = false;

        for (i, c) in input.chars().enumerate() {
            if c.is_uppercase() {
                if i > 0 && !prev_char_was_uppercase {
                    result.push('-');
                }
                result.push(c.to_lowercase().next().unwrap_or(c));
                prev_char_was_uppercase = true;
            } else {
                result.push(c);
                prev_char_was_uppercase = false;
            }
        }

        result
    }

    /// Convert a string to snake_case
    pub fn to_snake_case(input: &str) -> String {
        to_kebab_case(input).replace('-', "_")
    }
}

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

    #[test]
    fn test_kebab_case() {
        assert_eq!(string::to_kebab_case("HelloWorld"), "hello-world");
        assert_eq!(string::to_kebab_case("XMLHttpRequest"), "xmlhttp-request");
        assert_eq!(string::to_kebab_case("already-kebab"), "already-kebab");
    }

    #[test]
    fn test_snake_case() {
        assert_eq!(string::to_snake_case("HelloWorld"), "hello_world");
        assert_eq!(string::to_snake_case("XMLHttpRequest"), "xmlhttp_request");
    }
}
