//! Enterprise-grade configuration types for FMEA & Poka-Yoke marketplace framework.
//!
//! This module provides the data types for Fortune 500 enterprise features:
//! - Path protection (protected vs regenerate paths)
//! - Domain protection strategies
//! - Poka-Yoke error-proofing configuration

use serde::{Deserialize, Serialize};

/// Path protection strategy for domain code
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "kebab-case")]
pub enum DomainProtectionStrategy {
    /// Trait boundary: generated code defines traits, domain implements
    #[default]
    TraitBoundary,
    /// Module boundary: separate module directories
    ModuleBoundary,
    /// File boundary: separate files, no regeneration
    FileBoundary,
}

/// Protected path pattern (NEVER overwrite)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(transparent)]
pub struct ProtectedPath(pub String);

impl ProtectedPath {
    pub fn new(pattern: impl Into<String>) -> Self {
        Self(pattern.into())
    }

    pub fn pattern(&self) -> &str {
        &self.0
    }
}

/// Regeneratable path pattern (safe to overwrite)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(transparent)]
pub struct RegeneratePath(pub String);

impl RegeneratePath {
    pub fn new(pattern: impl Into<String>) -> Self {
        Self(pattern.into())
    }

    pub fn pattern(&self) -> &str {
        &self.0
    }
}

/// Generation configuration for path protection
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GenerationConfig {
    /// Paths that MUST NOT be modified by generation
    #[serde(default)]
    pub protected_paths: Vec<ProtectedPath>,
    /// Paths that CAN be regenerated freely
    #[serde(default)]
    pub regenerate_paths: Vec<RegeneratePath>,
}

impl GenerationConfig {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_protected(mut self, paths: Vec<&str>) -> Self {
        self.protected_paths = paths.into_iter().map(ProtectedPath::new).collect();
        self
    }

    pub fn with_regenerate(mut self, paths: Vec<&str>) -> Self {
        self.regenerate_paths = paths.into_iter().map(RegeneratePath::new).collect();
        self
    }
}

/// Enterprise-grade configuration
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EnterpriseConfig {
    /// Ready for Fortune 500 deployment
    #[serde(default)]
    pub fortune_500_ready: bool,
    /// FMEA controls enabled
    #[serde(default)]
    pub fmea_controls: bool,
    /// Poka-Yoke error proofing enabled
    #[serde(default)]
    pub poka_yoke_enabled: bool,
    /// Domain protection strategy
    #[serde(default)]
    pub domain_protection: DomainProtectionStrategy,
}

impl EnterpriseConfig {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn fortune_500() -> Self {
        Self {
            fortune_500_ready: true,
            fmea_controls: true,
            poka_yoke_enabled: true,
            domain_protection: DomainProtectionStrategy::TraitBoundary,
        }
    }
}

/// Poka-Yoke (error proofing) configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PokaYokeConfig {
    /// Header to inject into generated files
    pub generated_file_header: String,
    /// Patterns to add to .gitignore
    #[serde(default)]
    pub gitignore_patterns: Vec<String>,
    /// Patterns to mark in .gitattributes
    #[serde(default)]
    pub gitattributes_patterns: Vec<String>,
}

impl Default for PokaYokeConfig {
    fn default() -> Self {
        Self {
            generated_file_header: "DO NOT EDIT - This file is auto-generated by ggen".into(),
            gitignore_patterns: vec!["src/generated/".into()],
            gitattributes_patterns: vec!["src/generated/** linguist-generated=true".into()],
        }
    }
}

impl PokaYokeConfig {
    pub fn new() -> Self {
        Self::default()
    }

    /// Format header for a specific file type
    pub fn format_header(&self, extension: &str) -> String {
        let comment_prefix = match extension {
            "rs" | "ts" | "js" | "go" | "java" | "kt" | "swift" | "c" | "cpp" | "cs" => "//",
            "py" | "rb" | "sh" | "yaml" | "yml" | "toml" => "#",
            _ => "//",
        };

        self.generated_file_header
            .lines()
            .map(|line| format!("{} {}", comment_prefix, line))
            .collect::<Vec<_>>()
            .join("\n")
    }
}

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

    #[test]
    fn test_enterprise_config_default() {
        let config = EnterpriseConfig::default();
        assert!(!config.fortune_500_ready);
        assert!(!config.fmea_controls);
    }

    #[test]
    fn test_enterprise_config_fortune_500() {
        let config = EnterpriseConfig::fortune_500();
        assert!(config.fortune_500_ready);
        assert!(config.fmea_controls);
        assert!(config.poka_yoke_enabled);
        assert_eq!(
            config.domain_protection,
            DomainProtectionStrategy::TraitBoundary
        );
    }

    #[test]
    fn test_poka_yoke_format_header_rust() {
        let config = PokaYokeConfig::default();
        let header = config.format_header("rs");
        assert!(header.starts_with("//"));
    }

    #[test]
    fn test_poka_yoke_format_header_python() {
        let config = PokaYokeConfig::default();
        let header = config.format_header("py");
        assert!(header.starts_with("#"));
    }

    #[test]
    fn test_generation_config_builder() {
        let config = GenerationConfig::new()
            .with_protected(vec!["src/domain/**"])
            .with_regenerate(vec!["src/generated/**"]);

        assert_eq!(config.protected_paths.len(), 1);
        assert_eq!(config.regenerate_paths.len(), 1);
    }

    #[test]
    fn test_domain_protection_strategy_serde() {
        let strategy = DomainProtectionStrategy::TraitBoundary;
        let json = serde_json::to_string(&strategy).unwrap();
        assert_eq!(json, "\"trait-boundary\"");

        let parsed: DomainProtectionStrategy = serde_json::from_str("\"module-boundary\"").unwrap();
        assert_eq!(parsed, DomainProtectionStrategy::ModuleBoundary);
    }
}
