use std::path::PathBuf;

/// Configuration for the file indexer.
#[derive(Debug, Clone)]
pub struct Config {
    /// Whether to respect .gitignore files.
    pub respect_gitignore: bool,

    /// Whether to include hidden files/directories.
    pub include_hidden: bool,

    /// Maximum depth to traverse (None = unlimited).
    pub max_depth: Option<usize>,

    /// Only include files with these extensions (empty = all).
    pub extensions: Vec<String>,

    /// Exclude patterns (glob patterns).
    pub exclude_patterns: Vec<String>,

    /// Include patterns (glob patterns, empty = all).
    pub include_patterns: Vec<String>,

    /// Whether to follow symbolic links.
    pub follow_symlinks: bool,

    /// Whether to read file contents.
    pub read_contents: bool,

    /// Maximum file size to read contents (in bytes).
    pub max_content_size: u64,

    /// Additional paths to treat as gitignore files.
    pub custom_ignore_files: Vec<PathBuf>,

    /// Whether to use parallel traversal.
    pub parallel: bool,

    /// Number of threads for parallel traversal (0 = auto).
    pub threads: usize,

    /// Whether to parse code structure (functions, classes, etc.).
    /// Requires read_contents to be true.
    pub parse_structure: bool,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            respect_gitignore: true,
            include_hidden: false,
            max_depth: None,
            extensions: Vec::new(),
            exclude_patterns: Vec::new(),
            include_patterns: Vec::new(),
            follow_symlinks: false,
            read_contents: true,
            max_content_size: 10 * 1024 * 1024, // 10MB
            custom_ignore_files: Vec::new(),
            parallel: true,
            threads: 0,
            parse_structure: false,
        }
    }
}

impl Config {
    /// Create a new config builder.
    pub fn builder() -> ConfigBuilder {
        ConfigBuilder::default()
    }
}

/// Builder for Config.
#[derive(Debug, Clone, Default)]
pub struct ConfigBuilder {
    config: Config,
}

impl ConfigBuilder {
    /// Whether to respect .gitignore files (default: true).
    pub fn respect_gitignore(mut self, value: bool) -> Self {
        self.config.respect_gitignore = value;
        self
    }

    /// Whether to include hidden files (default: false).
    pub fn include_hidden(mut self, value: bool) -> Self {
        self.config.include_hidden = value;
        self
    }

    /// Maximum traversal depth (default: unlimited).
    pub fn max_depth(mut self, depth: Option<usize>) -> Self {
        self.config.max_depth = depth;
        self
    }

    /// Only include files with these extensions.
    pub fn extensions<I, S>(mut self, exts: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        self.config.extensions = exts.into_iter().map(|s| s.as_ref().to_string()).collect();
        self
    }

    /// Add an extension to include.
    pub fn extension<S: AsRef<str>>(mut self, ext: S) -> Self {
        self.config.extensions.push(ext.as_ref().to_string());
        self
    }

    /// Glob patterns to exclude.
    pub fn exclude_patterns<I, S>(mut self, patterns: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        self.config.exclude_patterns = patterns
            .into_iter()
            .map(|s| s.as_ref().to_string())
            .collect();
        self
    }

    /// Add an exclude pattern.
    pub fn exclude<S: AsRef<str>>(mut self, pattern: S) -> Self {
        self.config
            .exclude_patterns
            .push(pattern.as_ref().to_string());
        self
    }

    /// Glob patterns to include.
    pub fn include_patterns<I, S>(mut self, patterns: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        self.config.include_patterns = patterns
            .into_iter()
            .map(|s| s.as_ref().to_string())
            .collect();
        self
    }

    /// Add an include pattern.
    pub fn include<S: AsRef<str>>(mut self, pattern: S) -> Self {
        self.config
            .include_patterns
            .push(pattern.as_ref().to_string());
        self
    }

    /// Whether to follow symbolic links (default: false).
    pub fn follow_symlinks(mut self, value: bool) -> Self {
        self.config.follow_symlinks = value;
        self
    }

    /// Whether to read file contents (default: true).
    pub fn read_contents(mut self, value: bool) -> Self {
        self.config.read_contents = value;
        self
    }

    /// Maximum file size for content reading in bytes (default: 10MB).
    pub fn max_content_size(mut self, size: u64) -> Self {
        self.config.max_content_size = size;
        self
    }

    /// Add custom ignore files (like .gitignore).
    pub fn custom_ignore_files<I, P>(mut self, files: I) -> Self
    where
        I: IntoIterator<Item = P>,
        P: Into<PathBuf>,
    {
        self.config.custom_ignore_files = files.into_iter().map(Into::into).collect();
        self
    }

    /// Add a custom ignore file.
    pub fn custom_ignore_file<P: Into<PathBuf>>(mut self, file: P) -> Self {
        self.config.custom_ignore_files.push(file.into());
        self
    }

    /// Whether to use parallel traversal (default: true).
    pub fn parallel(mut self, value: bool) -> Self {
        self.config.parallel = value;
        self
    }

    /// Number of threads for parallel traversal (0 = auto, default: 0).
    pub fn threads(mut self, count: usize) -> Self {
        self.config.threads = count;
        self
    }

    /// Whether to parse code structure (default: false).
    ///
    /// When enabled, files will include parsed symbols like functions,
    /// classes, structs, imports, etc. Requires `read_contents` to be true.
    pub fn parse_structure(mut self, value: bool) -> Self {
        self.config.parse_structure = value;
        self
    }

    /// Build the configuration.
    pub fn build(self) -> Config {
        self.config
    }
}
