// SPDX-License-Identifier: MIT
// Copyright (c) 2025-2026 SenWeaverCoding
// Licensed under the MIT License.

use super::traits::MemoryCategory;
use crate::config::MemoryPolicyConfig;

pub struct PolicyEnforcer {
    config: MemoryPolicyConfig,
}

impl PolicyEnforcer {
    pub fn new(config: &MemoryPolicyConfig) -> Self {
        Self {
            config: config.clone(),
        }
    }

    pub fn is_read_only(&self, namespace: &str) -> bool {
        self.config
            .read_only_namespaces
            .iter()
            .any(|ns| ns == namespace)
    }

    pub fn validate_store(
        &self,
        namespace: &str,
        _category: &MemoryCategory,
    ) -> Result<(), PolicyViolation> {
        if self.is_read_only(namespace) {
            return Err(PolicyViolation::ReadOnlyNamespace(namespace.to_string()));
        }
        Ok(())
    }

    pub fn check_namespace_limit(&self, current_count: usize) -> Result<(), PolicyViolation> {
        if self.config.max_entries_per_namespace > 0
            && current_count >= self.config.max_entries_per_namespace
        {
            return Err(PolicyViolation::NamespaceQuotaExceeded {
                max: self.config.max_entries_per_namespace,
                current: current_count,
            });
        }
        Ok(())
    }

    pub fn check_category_limit(&self, current_count: usize) -> Result<(), PolicyViolation> {
        if self.config.max_entries_per_category > 0
            && current_count >= self.config.max_entries_per_category
        {
            return Err(PolicyViolation::CategoryQuotaExceeded {
                max: self.config.max_entries_per_category,
                current: current_count,
            });
        }
        Ok(())
    }

    pub fn retention_days_for_category(&self, category: &MemoryCategory, default_days: u32) -> u32 {
        let key = category.to_string();
        self.config
            .retention_days_by_category
            .get(&key)
            .copied()
            .unwrap_or(default_days)
    }
}

#[derive(Debug, Clone)]
pub enum PolicyViolation {
    ReadOnlyNamespace(String),
    NamespaceQuotaExceeded { max: usize, current: usize },
    CategoryQuotaExceeded { max: usize, current: usize },
}

impl std::fmt::Display for PolicyViolation {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::ReadOnlyNamespace(ns) => write!(f, "namespace '{ns}' is read-only"),
            Self::NamespaceQuotaExceeded { max, current } => {
                write!(f, "namespace quota exceeded: {current}/{max} entries")
            }
            Self::CategoryQuotaExceeded { max, current } => {
                write!(f, "category quota exceeded: {current}/{max} entries")
            }
        }
    }
}

impl std::error::Error for PolicyViolation {}
