//! Version Control System (VCS) storage provider abstraction.
//!
//! This module provides a modular architecture for integrating multiple version
//! control systems as `StorageBackend` implementations. Instead of each VCS
//! duplicating serialization, query filtering, and batching logic, a two-layer
//! design separates concerns:
//!
//! 1. **`VcsProvider` trait** — Simple interface for VCS-specific operations
//!    (read/write objects, create versions, health checks).
//!
//! 2. **`VcsStorageBackend<P: VcsProvider>`** — Generic adapter that implements
//!    `StorageBackend` on top of any `VcsProvider`, handling JSON serialization,
//!    query filtering, path management, and batch flush semantics.
//!
//! ## Supported Providers
//!
//! | Provider     | Feature Flag       | Protocol           |
//! |-------------|--------------------|--------------------|
//! | DVC          | `vcs-dvc`          | Git + filesystem   |
//! | Nessie       | `vcs-nessie`       | REST API (v2)      |
//! | Pachyderm    | `vcs-pachyderm`    | REST API           |
//! | ArtiVC       | `vcs-artivc`       | CLI + filesystem   |
//! | DuckLake     | `vcs-ducklake`     | Filesystem + JSON  |
//! | Iceberg      | `vcs-iceberg`      | REST Catalog API   |
//! | Git+LFS      | `vcs-gitlfs`       | Git + LFS          |
//!
//! ## Usage
//!
//! ```rust,ignore
//! use briefcase_core::storage::vcs::{VcsStorageBackend, VcsProviderConfig, create_vcs_backend};
//!
//! // From environment variables
//! let backend = create_vcs_backend_from_env("nessie").await?;
//!
//! // Or explicit config
//! let config = VcsProviderConfig::new("nessie")
//!     .with_endpoint("https://nessie.example.com")
//!     .with_branch("main");
//! let backend = create_vcs_backend(config).await?;
//! ```
//!
//! ## Adding a New Provider
//!
//! 1. Create a new module under `vcs/` (e.g., `vcs/myprovider/mod.rs`)
//! 2. Implement `VcsProvider` trait (~150-250 lines)
//! 3. Add a feature flag in `Cargo.toml` (e.g., `vcs-myprovider = ["vcs-storage"]`)
//! 4. Register in the `create_vcs_provider()` factory below

pub mod adapter;
pub mod provider;

#[cfg(feature = "vcs-artivc")]
pub mod artivc;
#[cfg(feature = "vcs-ducklake")]
pub mod ducklake;
#[cfg(feature = "vcs-dvc")]
pub mod dvc;
#[cfg(feature = "vcs-gitlfs")]
pub mod gitlfs;
#[cfg(feature = "vcs-iceberg")]
pub mod iceberg;
#[cfg(feature = "vcs-nessie")]
pub mod nessie;
#[cfg(feature = "vcs-pachyderm")]
pub mod pachyderm;

// Re-export core types
pub use adapter::VcsStorageBackend;
pub use provider::{ObjectMetadata, VcsProvider, VcsProviderConfig};

use super::StorageError;

/// Create a `VcsProvider` instance from configuration.
///
/// Dispatches to the appropriate provider constructor based on `config.provider_type`.
/// Returns `StorageError::ConnectionError` for unknown provider types.
///
/// # Feature Gates
///
/// Each provider is only available when its corresponding feature flag is enabled.
/// Attempting to create an unsupported provider returns a descriptive error.
pub async fn create_vcs_provider(
    config: VcsProviderConfig,
) -> Result<Box<dyn VcsProvider>, StorageError> {
    match config.provider_type.as_str() {
        #[cfg(feature = "vcs-dvc")]
        "dvc" => Ok(Box::new(dvc::DvcProvider::new(config)?)),

        #[cfg(feature = "vcs-nessie")]
        "nessie" => Ok(Box::new(nessie::NessieProvider::new(config)?)),

        #[cfg(feature = "vcs-pachyderm")]
        "pachyderm" => Ok(Box::new(pachyderm::PachydermProvider::new(config)?)),

        #[cfg(feature = "vcs-artivc")]
        "artivc" => Ok(Box::new(artivc::ArtiVcProvider::new(config)?)),

        #[cfg(feature = "vcs-ducklake")]
        "ducklake" => Ok(Box::new(ducklake::DuckLakeProvider::new(config)?)),

        #[cfg(feature = "vcs-iceberg")]
        "iceberg" => Ok(Box::new(iceberg::IcebergProvider::new(config)?)),

        #[cfg(feature = "vcs-gitlfs")]
        "gitlfs" | "git-lfs" | "git_lfs" => Ok(Box::new(gitlfs::GitLfsProvider::new(config)?)),

        other => Err(StorageError::ConnectionError(format!(
            "Unknown or disabled VCS provider: '{}'. \
             Available providers (when feature-enabled): dvc, nessie, pachyderm, \
             artivc, ducklake, iceberg, gitlfs",
            other
        ))),
    }
}

/// Create a `VcsStorageBackend` from configuration.
///
/// Convenience function that creates the provider and wraps it in the generic adapter.
pub async fn create_vcs_backend(
    config: VcsProviderConfig,
) -> Result<VcsStorageBackend<Box<dyn VcsProvider>>, StorageError> {
    let provider = create_vcs_provider(config).await?;
    Ok(VcsStorageBackend::new(provider))
}

/// Create a `VcsStorageBackend` from environment variables.
///
/// Reads configuration from `BRIEFCASE_{PROVIDER}_*` environment variables.
///
/// # Example
///
/// ```bash
/// export BRIEFCASE_NESSIE_ENDPOINT="https://nessie.example.com"
/// export BRIEFCASE_NESSIE_BRANCH="main"
/// ```
///
/// ```rust,ignore
/// let backend = create_vcs_backend_from_env("nessie").await?;
/// ```
pub async fn create_vcs_backend_from_env(
    provider_type: &str,
) -> Result<VcsStorageBackend<Box<dyn VcsProvider>>, StorageError> {
    let config = VcsProviderConfig::from_env(provider_type);
    create_vcs_backend(config).await
}

/// List all VCS provider types that are compiled into this build.
///
/// Useful for diagnostics and configuration validation.
pub fn available_providers() -> Vec<&'static str> {
    let mut providers = Vec::new();

    #[cfg(feature = "vcs-dvc")]
    providers.push("dvc");
    #[cfg(feature = "vcs-nessie")]
    providers.push("nessie");
    #[cfg(feature = "vcs-pachyderm")]
    providers.push("pachyderm");
    #[cfg(feature = "vcs-artivc")]
    providers.push("artivc");
    #[cfg(feature = "vcs-ducklake")]
    providers.push("ducklake");
    #[cfg(feature = "vcs-iceberg")]
    providers.push("iceberg");
    #[cfg(feature = "vcs-gitlfs")]
    providers.push("gitlfs");

    providers
}

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

    #[test]
    fn test_available_providers_returns_list() {
        let providers = available_providers();
        // At minimum, the list should be a valid Vec (may be empty without features)
        assert!(providers.len() <= 7);
    }

    #[tokio::test]
    async fn test_unknown_provider_returns_error() {
        let config = VcsProviderConfig::new("nonexistent_vcs");
        let result = create_vcs_provider(config).await;
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(matches!(err, StorageError::ConnectionError(_)));
    }
}
