/// Team Policy Pack: Baseline Authority Contract Definitions
///
/// This module provides canonical baseline team contracts that enforce
/// least-privilege access patterns:
/// - ReadOnly: No vault modification, full env inheritance
/// - CIDeploy: Hardened deployment target lock-down, no vault modification
/// - OpsEmergency: Time-limited emergency access with audit compliance
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Baseline authority contract template
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BaselineContract {
    pub name: String,
    pub description: String,
    pub required_trust_profile: String,
    pub access_level: AccessLevel,
    pub secret_constraints: SecretConstraints,
    pub target_constraints: Option<Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccessLevel {
    ReadOnly,
    ReadWrite,
}

impl std::fmt::Display for AccessLevel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AccessLevel::ReadOnly => write!(f, "read_only"),
            AccessLevel::ReadWrite => write!(f, "read_write"),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecretConstraints {
    /// Secrets allowed to be injected (empty = all)
    pub allowed_secrets: Vec<String>,
    /// Secrets that must exist or the exec fails
    pub required_secrets: Vec<String>,
}

/// Read-only team member access contract.
///
/// Grants access to retrieve secrets without modification capability.
/// Suitable for developers, analysts, and read-only operators.
pub fn read_only_contract() -> BaselineContract {
    BaselineContract {
        name: "read_only".to_string(),
        description: "Read-only access: retrieve secrets, no vault modifications".to_string(),
        required_trust_profile: "standard".to_string(),
        access_level: AccessLevel::ReadOnly,
        secret_constraints: SecretConstraints {
            allowed_secrets: vec![],
            required_secrets: vec![],
        },
        target_constraints: None,
    }
}

/// CI deployment contract with hardened trust.
///
/// For automated CI/CD pipelines. Enforces minimal env inheritance,
/// target validation, and read-only vault access.
pub fn ci_deploy_contract(targets: Vec<String>) -> BaselineContract {
    BaselineContract {
        name: "ci_deploy".to_string(),
        description: "CI deployment: hardened env, target-restricted, read-only vault".to_string(),
        required_trust_profile: "hardened".to_string(),
        access_level: AccessLevel::ReadOnly,
        secret_constraints: SecretConstraints {
            allowed_secrets: vec![
                "AWS_ACCOUNT_ID".to_string(),
                "AWS_ACCESS_KEY_ID".to_string(),
                "AWS_SECRET_ACCESS_KEY".to_string(),
                "TERRAFORM_TOKEN".to_string(),
            ],
            required_secrets: vec![
                "AWS_ACCESS_KEY_ID".to_string(),
                "AWS_SECRET_ACCESS_KEY".to_string(),
            ],
        },
        target_constraints: Some(targets),
    }
}

/// Operations emergency contract for time-limited incident response.
///
/// Allows read-write vault access for emergency remediation but enforces
/// hardened env, strict target validation, and comprehensive audit logging.
pub fn ops_emergency_contract() -> BaselineContract {
    BaselineContract {
        name: "ops_emergency".to_string(),
        description: "Operations emergency: hardened env, write access, strict targeting"
            .to_string(),
        required_trust_profile: "hardened".to_string(),
        access_level: AccessLevel::ReadWrite,
        secret_constraints: SecretConstraints {
            allowed_secrets: vec![
                "ADMIN_SSH_KEY".to_string(),
                "SUDO_PASSWORD".to_string(),
                "INCIDENT_TICKET_TOKEN".to_string(),
            ],
            required_secrets: vec!["ADMIN_SSH_KEY".to_string()],
        },
        target_constraints: Some(vec!["ssh".to_string(), "sudo".to_string()]),
    }
}

/// Registry of all baseline contracts.
pub fn baseline_contracts() -> HashMap<&'static str, BaselineContract> {
    let mut contracts = HashMap::new();

    contracts.insert("read_only", read_only_contract());
    contracts.insert(
        "ci_deploy",
        ci_deploy_contract(vec!["terraform".to_string(), "ansible".to_string()]),
    );
    contracts.insert("ops_emergency", ops_emergency_contract());

    contracts
}

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

    #[test]
    fn test_read_only_contract_no_restrictions() {
        let contract = read_only_contract();
        assert_eq!(contract.access_level.to_string(), "read_only");
        assert!(contract.secret_constraints.allowed_secrets.is_empty());
        assert!(contract.target_constraints.is_none());
    }

    #[test]
    fn test_ci_deploy_contract_has_required_secrets() {
        let contract = ci_deploy_contract(vec!["terraform".to_string()]);
        assert_eq!(contract.access_level.to_string(), "read_only");
        assert!(!contract.secret_constraints.required_secrets.is_empty());
        assert!(contract.target_constraints.is_some());
        assert_eq!(contract.required_trust_profile, "hardened");
    }

    #[test]
    fn test_ops_emergency_contract_allows_write() {
        let contract = ops_emergency_contract();
        assert_eq!(contract.access_level.to_string(), "read_write");
        assert_eq!(contract.required_trust_profile, "hardened");
        let targets = contract.target_constraints.unwrap();
        assert!(targets.contains(&"ssh".to_string()));
    }

    #[test]
    fn test_baseline_contracts_registry_is_complete() {
        let registry = baseline_contracts();
        assert!(registry.contains_key("read_only"));
        assert!(registry.contains_key("ci_deploy"));
        assert!(registry.contains_key("ops_emergency"));
    }
}
