//! Configuration file discovery and reading with multiple format support.
//!
//! This crate provides functionality to find and read configuration files
//! in various formats (TOML, JSON, YAML) following platform conventions
//! provided by `cfgmatic-paths`.
//!
//! # Quick Start
//!
//! ```
//! use cfgmatic_files::FileFinder;
//!
//! // Find all config files for an application
//! let files = FileFinder::new("myapp").find().expect("find config files");
//!
//! for mut file in files {
//!     println!("Found: {} ({:?})", file.path.display(), file.tier);
//! }
//! ```
//!
//! # Parsing Configurations
//!
//! ```
//! use cfgmatic_files::FileFinder;
//! use serde::Deserialize;
//!
//! #[derive(Debug, Deserialize)]
//! struct Config {
//!     timeout: u32,
//!     host: String,
//! }
//!
//! let files = FileFinder::new("myapp").find().expect("find config files");
//!
//! if let Some(mut file) = files.first().cloned() {
//!     let config: Config = file.parse().expect("parse config");
//!     println!("Timeout: {}, Host: {}", config.timeout, config.host);
//! }
//! ```
//!
//! # Supported Formats
//!
//! - **TOML** (feature: `toml`, enabled by default)
//! - **JSON** (feature: `json`, enabled by default)
//! - **YAML** (feature: `yaml`) - **LEGACY**: `serde_yaml` is deprecated by the author.
//!   YAML support may be removed in future versions.
//!
//! # Configuration Priority
//!
//! Files are searched and prioritized by tier (highest to lowest):
//!
//! 1. **User** - User-specific configs (`~/.config/myapp/`)
//! 2. **Local** - Machine-specific configs (`/usr/local/etc/myapp/`)
//! 3. **System** - System-wide configs (`/etc/myapp/`)
//!
//! When merging configurations, higher tiers override lower tiers.

// TODO: Remove these allows when refactoring existing code
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::multiple_bound_locations)]
#![allow(clippy::type_repetition_in_bounds)]
#![allow(clippy::return_self_not_must_use)]
#![allow(clippy::unnecessary_wraps)]
#![allow(clippy::manual_let_else)]
#![allow(clippy::items_after_statements)]
#![warn(missing_docs)]

pub use error::{FileError, Result};
pub use file::{ConfigFile, ConfigFiles, Mergeable};
pub use finder::{FileFinder, FileFinderState, find_files, find_first_file, load_first};
pub use format::Format;

// Re-export from cfgmatic-paths for convenience
pub use cfgmatic_paths::ConfigTier;

mod error;
mod file;
mod finder;
mod format;

/// Convenience functions for common operations.
pub mod prelude {
    //! Common imports for working with configuration files.

    pub use crate::{
        ConfigFile, ConfigFiles, ConfigTier, FileFinder, FileFinderState, Format, Mergeable,
        Result, find_files, find_first_file, load_first,
    };
}

/// Load and merge configuration from all found files.
///
/// Files are merged in priority order with higher tiers overriding
/// values from lower tiers.
///
/// # Example
///
/// ```
/// use cfgmatic_files::load_merged;
///
/// match load_merged::<serde_json::Value>("myapp") {
///     Ok(config) => println!("Loaded: {:?}", config),
///     Err(e) => eprintln!("Failed to load config: {}", e),
/// }
/// ```
pub fn load_merged<T: serde::de::DeserializeOwned + Mergeable + Default>(
    app_name: impl Into<String>,
) -> Result<T> {
    let mut files = FileFinder::new(app_name).find()?;
    files.merge()
}

/// Find configuration files with a specific format.
///
/// # Example
///
/// ```
/// use cfgmatic_files::find_with_format;
///
/// let files = find_with_format("myapp", cfgmatic_files::Format::Toml)
///     .expect("find toml files");
/// ```
pub fn find_with_format(app_name: impl Into<String>, format: Format) -> Result<ConfigFiles> {
    FileFinder::new(app_name).formats(&[format]).find()
}

/// Check if a configuration exists for the application.
///
/// Returns `true` if at least one configuration file is found.
pub fn config_exists(app_name: impl Into<String>) -> bool {
    find_first_file(app_name)
        .map(|f| f.is_some())
        .unwrap_or(false)
}

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

    #[test]
    fn test_module_exports() {
        // Just verify all public types are accessible
        let _: FileFinder = FileFinder::new("test");
        let _: Format = Format::Toml;
    }

    #[test]
    fn test_config_exists_nonexistent() {
        assert!(!config_exists("nonexistent_app_12345"));
    }
}
