#![allow(dead_code)]

use std::sync::Arc;
use std::time::{Duration, Instant};

use anyhow::Result;
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use tracing::info;

use crate::discovery::ServiceDiscovery;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyDecision {
    pub allow: bool,
    pub mode: String, // mtls/tls/plain
    pub reason: String,
}

pub struct PolicyEnforcer {
    discovery: Arc<ServiceDiscovery>,
    default_mode: String,
    cache: Arc<RwLock<std::collections::HashMap<String, (PolicyDecision, Instant)>>>,
}

impl PolicyEnforcer {
    pub fn new(discovery: Arc<ServiceDiscovery>, default_mode: String) -> Self {
        Self {
            discovery,
            default_mode,
            cache: Arc::new(RwLock::new(std::collections::HashMap::new())),
        }
    }

    pub async fn evaluate(
        &self,
        source_service: &str,
        target_service: &str,
    ) -> Result<PolicyDecision> {
        let cache_key = format!("{}->{}", source_service, target_service);

        // キャッシュをチェック
        {
            let cache = self.cache.read().await;
            if let Some((decision, timestamp)) = cache.get(&cache_key) {
                if timestamp.elapsed() < Duration::from_secs(30) {
                    return Ok(decision.clone());
                }
            }
        }

        // Chainfireからポリシーを取得
        let policy = self
            .discovery
            .get_mtls_policy(source_service, target_service)
            .await?;

        let decision = if let Some(p) = policy {
            PolicyDecision {
                allow: true,
                mode: p.mode.unwrap_or_else(|| {
                    if p.mtls_required.unwrap_or(false) {
                        "mtls".to_string()
                    } else {
                        "plain".to_string()
                    }
                }),
                reason: format!("policy {} applied", p.policy_id),
            }
        } else {
            PolicyDecision {
                allow: true,
                mode: self.default_mode.clone(),
                reason: "default policy applied".to_string(),
            }
        };

        // キャッシュに保存
        {
            let mut cache = self.cache.write().await;
            cache.insert(cache_key, (decision.clone(), Instant::now()));
        }

        info!(
            source = source_service,
            target = target_service,
            mode = %decision.mode,
            "policy decision"
        );

        Ok(decision)
    }

    pub async fn start_background_refresh(&self) {
        let cache = Arc::clone(&self.cache);
        tokio::spawn(async move {
            let mut interval = tokio::time::interval(Duration::from_secs(60));
            loop {
                interval.tick().await;

                // キャッシュをクリア（簡易実装）
                {
                    let mut cache_guard = cache.write().await;
                    cache_guard.clear();
                }

                info!("policy cache cleared, will be refreshed on next request");
            }
        });
    }
}
