//! Configuration module

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Main configuration for cargo-governor
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GovernorConfig {
    /// Versioning configuration
    pub versioning: VersioningConfig,
    /// Changelog configuration
    pub changelog: ChangelogConfig,
    /// Publish configuration
    pub publish: PublishConfig,
    /// Git configuration
    pub git: GitConfig,
    /// CI configuration
    pub ci: CiConfig,
}

impl Default for GovernorConfig {
    fn default() -> Self {
        Self {
            versioning: VersioningConfig::default(),
            changelog: ChangelogConfig::default(),
            publish: PublishConfig::default(),
            git: GitConfig::default(),
            ci: CiConfig::default(),
        }
    }
}

/// Versioning configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersioningConfig {
    /// Scheme to use for versioning
    pub scheme: VersionScheme,
    /// Whether workspace uses shared version
    pub shared_version: bool,
    /// Prerelease prefix
    pub prerelease_prefix: Option<String>,
}

impl Default for VersioningConfig {
    fn default() -> Self {
        Self {
            scheme: VersionScheme::Conventional,
            shared_version: true,
            prerelease_prefix: None,
        }
    }
}

/// Version scheme
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum VersionScheme {
    /// Conventional commits
    Conventional,
    /// Manual versioning
    Manual,
    /// Calendar versioning
    CalVer,
}

/// Changelog configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChangelogConfig {
    /// Whether changelog generation is enabled
    pub enabled: bool,
    /// Path to changelog file
    pub path: String,
    /// Format type
    pub format: ChangelogFormat,
    /// Whether to append to existing changelog
    pub incremental: bool,
}

impl Default for ChangelogConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            path: "CHANGELOG.md".to_string(),
            format: ChangelogFormat::KeepAChangelog,
            incremental: true,
        }
    }
}

/// Changelog format
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ChangelogFormat {
    KeepAChangelog,
    GitHubReleases,
    Json,
}

/// Publish configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PublishConfig {
    /// Automatically determine publish order
    pub auto_order: bool,
    /// Delay between publishes in seconds
    pub delay_secs: u64,
    /// Max retries per crate
    pub max_retries: usize,
    /// Error handling strategy
    pub error_handling: super::traits::workflow_step::ErrorHandlingStrategy,
}

impl Default for PublishConfig {
    fn default() -> Self {
        Self {
            auto_order: true,
            delay_secs: 10,
            max_retries: 3,
            error_handling: super::traits::workflow_step::ErrorHandlingStrategy::Stop,
        }
    }
}

/// Git configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GitConfig {
    /// Whether git operations are enabled
    pub enabled: bool,
    /// Whether to create commits
    pub commit: bool,
    /// Whether to create tags
    pub tag: bool,
    /// Push behavior
    pub push: PushBehavior,
    /// Commit message template
    pub commit_template: Option<String>,
    /// Tag template
    pub tag_template: Option<String>,
}

impl Default for GitConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            commit: true,
            tag: true,
            push: PushBehavior::Auto,
            commit_template: Some("chore(release): bump version to {version}".to_string()),
            tag_template: Some("v{version}".to_string()),
        }
    }
}

/// Push behavior
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PushBehavior {
    Auto,
    Always,
    Never,
}

/// CI configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CiConfig {
    /// Auto-detect CI environment
    pub auto_detect: bool,
    /// Whether to confirm in CI (should be false)
    pub confirm: bool,
    /// Output format for CI
    pub format: OutputFormat,
}

impl Default for CiConfig {
    fn default() -> Self {
        Self {
            auto_detect: true,
            confirm: false,
            format: OutputFormat::Json,
        }
    }
}

/// Output format
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OutputFormat {
    Json,
    Yaml,
    Human,
}

/// Load configuration from a file
pub fn load_config(path: &PathBuf) -> super::Result<GovernorConfig> {
    let contents = std::fs::read_to_string(path).map_err(|e| super::Error::Io(e))?;
    let config: GovernorConfig = toml::from_str(&contents)
        .map_err(|e| super::Error::Serialization(e.to_string()))?;
    Ok(config)
}
