//! SurrealDB Policy Storage Implementation
//!
//! Provides SurrealDB backend for policy storage with versioning and audit
//! trails.

// TODO: Re-enable when policies module is fixed
// use crate::policies::{PolicyMetadata, PolicyVersion, PolicyCategory};
// use crate::policies::versioning::RollbackResult;

// Temporary placeholder types until policies module is enabled
use serde::{Deserialize, Serialize};

use super::{
    ComplianceCheckResult, PolicyEvaluationEvent, PolicyMetrics, PolicySearchQuery, PolicyStorage,
};
use crate::error::{auth, policy, ControlCenterError, Result};
use crate::services::secrets::SecretType;
use crate::simple_config::Config;

#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
pub struct PolicyMetadata {
    pub id: String,
    pub name: String,
    pub description: String,
    pub version: String,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
    pub created_by: String,
    pub tags: Vec<String>,
    pub category: String,
    pub priority: u32,
    pub enabled: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
pub struct PolicyVersion {
    pub version_id: String,
    pub policy_id: String,
    pub version_number: u32,
    pub content: String,
    pub is_active: bool,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub tags: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RollbackResult {
    pub success: bool,
    pub from_version: u32,
    pub to_version: u32,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}

use async_trait::async_trait;
use surrealdb::engine::local::Mem;
use surrealdb::engine::remote::ws::{Client, Ws};
use surrealdb::types::{RecordId, SurrealValue};
use surrealdb::Surreal;
use tracing::{debug, info};
use uuid::Uuid;

/// SurrealDB record for policies
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
struct PolicyRecord {
    pub id: RecordId,
    pub policy_id: String,
    pub content: String,
    pub metadata: PolicyMetadata,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

/// SurrealDB record for policy versions
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
struct PolicyVersionRecord {
    pub id: RecordId,
    pub version: PolicyVersion,
}

/// SurrealDB record for policy evaluations
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
struct PolicyEvaluationRecord {
    pub id: RecordId,
    pub evaluation: PolicyEvaluationEvent,
}

/// SurrealDB record for compliance checks
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
struct ComplianceCheckRecord {
    pub id: RecordId,
    pub result: ComplianceCheckResult,
}

/// SurrealDB storage implementation
pub struct SurrealDbPolicyStorage<T: surrealdb::Connection = Client> {
    db: Surreal<T>,
    /// Namespace used for initialization
    #[allow(dead_code)]
    namespace: String,
    /// Database name used for initialization
    #[allow(dead_code)]
    database: String,
}

impl SurrealDbPolicyStorage<Client> {
    /// Create new SurrealDB storage with remote connection
    pub async fn new(config: &Config) -> Result<Self> {
        let db = Surreal::new::<Ws>(&config.database.url).await?;

        // Sign in if credentials provided
        if let (Some(username), Some(password)) =
            (&config.database.username, &config.database.password)
        {
            db.signin(surrealdb::opt::auth::Root {
                username: username.clone(),
                password: password.clone(),
            })
            .await?;
        }

        // Use namespace and database
        db.use_ns(&config.database.namespace)
            .use_db(&config.database.database)
            .await?;

        let storage = Self {
            db,
            namespace: config.database.namespace.clone(),
            database: config.database.database.clone(),
        };

        // Initialize schema
        storage.initialize_schema().await?;

        info!("Connected to SurrealDB at {}", config.database.url);
        Ok(storage)
    }

    /// Initialize database schema
    async fn initialize_schema(&self) -> Result<()> {
        // Create tables with proper schemas
        self.db
            .query(
                r#"
            DEFINE TABLE IF NOT EXISTS policies SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS policy_id ON TABLE policies TYPE string;
            DEFINE FIELD IF NOT EXISTS content ON TABLE policies TYPE string;
            DEFINE FIELD IF NOT EXISTS metadata ON TABLE policies TYPE object;
            DEFINE FIELD IF NOT EXISTS created_at ON TABLE policies TYPE datetime;
            DEFINE FIELD IF NOT EXISTS updated_at ON TABLE policies TYPE datetime;
            DEFINE INDEX IF NOT EXISTS policy_id_idx ON TABLE policies COLUMNS policy_id UNIQUE;
            DEFINE INDEX IF NOT EXISTS enabled_idx ON TABLE policies COLUMNS metadata.enabled;
            DEFINE INDEX IF NOT EXISTS category_idx ON TABLE policies COLUMNS metadata.category;
        "#,
            )
            .await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS policy_versions SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS version ON TABLE policy_versions TYPE object;
            DEFINE INDEX IF NOT EXISTS policy_version_idx ON TABLE policy_versions COLUMNS version.policy_id, version.version_number UNIQUE;
            DEFINE INDEX IF NOT EXISTS active_version_idx ON TABLE policy_versions COLUMNS version.policy_id, version.is_active;
        "#).await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS policy_evaluations SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS evaluation ON TABLE policy_evaluations TYPE object;
            DEFINE INDEX IF NOT EXISTS evaluation_policy_idx ON TABLE policy_evaluations COLUMNS evaluation.policy_id;
            DEFINE INDEX IF NOT EXISTS evaluation_timestamp_idx ON TABLE policy_evaluations COLUMNS evaluation.timestamp;
        "#).await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS compliance_checks SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS result ON TABLE compliance_checks TYPE object;
            DEFINE INDEX IF NOT EXISTS compliance_framework_idx ON TABLE compliance_checks COLUMNS result.framework;
            DEFINE INDEX IF NOT EXISTS compliance_timestamp_idx ON TABLE compliance_checks COLUMNS result.timestamp;
        "#).await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS rollback_operations SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS policy_id ON TABLE rollback_operations TYPE string;
            DEFINE FIELD IF NOT EXISTS rollback ON TABLE rollback_operations TYPE object;
            DEFINE INDEX IF NOT EXISTS rollback_policy_idx ON TABLE rollback_operations COLUMNS policy_id;
        "#).await?;

        // Create vault secrets tables
        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS vault_secrets SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS path ON TABLE vault_secrets TYPE string;
            DEFINE FIELD IF NOT EXISTS encrypted_value ON TABLE vault_secrets TYPE string;
            DEFINE FIELD IF NOT EXISTS version ON TABLE vault_secrets TYPE int;
            DEFINE FIELD IF NOT EXISTS created_at ON TABLE vault_secrets TYPE datetime;
            DEFINE FIELD IF NOT EXISTS updated_at ON TABLE vault_secrets TYPE datetime;
            DEFINE FIELD IF NOT EXISTS created_by ON TABLE vault_secrets TYPE string;
            DEFINE FIELD IF NOT EXISTS updated_by ON TABLE vault_secrets TYPE string;
            DEFINE FIELD IF NOT EXISTS deleted ON TABLE vault_secrets TYPE bool;
            DEFINE FIELD IF NOT EXISTS encryption_context ON TABLE vault_secrets TYPE option<string>;
            DEFINE FIELD IF NOT EXISTS metadata ON TABLE vault_secrets TYPE option<object>;

            -- NEW: Hierarchy fields for workspace isolation
            DEFINE FIELD IF NOT EXISTS workspace_id ON TABLE vault_secrets TYPE string;
            DEFINE FIELD IF NOT EXISTS infra_id ON TABLE vault_secrets TYPE option<string>;
            DEFINE FIELD IF NOT EXISTS domain ON TABLE vault_secrets TYPE string;

            -- NEW: Secret type classification
            DEFINE FIELD IF NOT EXISTS secret_type ON TABLE vault_secrets TYPE string;

            -- NEW: Organization fields
            DEFINE FIELD IF NOT EXISTS tags ON TABLE vault_secrets TYPE array<string>;

            -- NEW: Lifecycle fields
            DEFINE FIELD IF NOT EXISTS ttl_seconds ON TABLE vault_secrets TYPE option<int>;
            DEFINE FIELD IF NOT EXISTS auto_rotate ON TABLE vault_secrets TYPE bool;
            DEFINE FIELD IF NOT EXISTS rotation_interval_days ON TABLE vault_secrets TYPE option<int>;

            -- Updated indexes for workspace isolation
            DEFINE INDEX IF NOT EXISTS vault_path_idx ON TABLE vault_secrets COLUMNS path UNIQUE;
            DEFINE INDEX IF NOT EXISTS vault_deleted_idx ON TABLE vault_secrets COLUMNS deleted;
            DEFINE INDEX IF NOT EXISTS vault_workspace_idx ON TABLE vault_secrets COLUMNS workspace_id;
            DEFINE INDEX IF NOT EXISTS vault_domain_idx ON TABLE vault_secrets COLUMNS workspace_id, domain;
            DEFINE INDEX IF NOT EXISTS vault_hierarchy_idx ON TABLE vault_secrets COLUMNS workspace_id, infra_id, domain;
        "#).await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS vault_versions SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS secret_id ON TABLE vault_versions TYPE string;
            DEFINE FIELD IF NOT EXISTS path ON TABLE vault_versions TYPE string;
            DEFINE FIELD IF NOT EXISTS encrypted_value ON TABLE vault_versions TYPE string;
            DEFINE FIELD IF NOT EXISTS version ON TABLE vault_versions TYPE int;
            DEFINE FIELD IF NOT EXISTS created_at ON TABLE vault_versions TYPE datetime;
            DEFINE FIELD IF NOT EXISTS created_by ON TABLE vault_versions TYPE string;
            DEFINE FIELD IF NOT EXISTS encryption_context ON TABLE vault_versions TYPE option<string>;
            DEFINE FIELD IF NOT EXISTS metadata ON TABLE vault_versions TYPE option<object>;

            -- NEW: Hierarchy fields for workspace isolation
            DEFINE FIELD IF NOT EXISTS workspace_id ON TABLE vault_versions TYPE string;
            DEFINE FIELD IF NOT EXISTS infra_id ON TABLE vault_versions TYPE option<string>;
            DEFINE FIELD IF NOT EXISTS domain ON TABLE vault_versions TYPE string;

            -- NEW: Secret type classification
            DEFINE FIELD IF NOT EXISTS secret_type ON TABLE vault_versions TYPE string;

            -- NEW: Organization fields
            DEFINE FIELD IF NOT EXISTS tags ON TABLE vault_versions TYPE array<string>;

            -- NEW: Lifecycle fields
            DEFINE FIELD IF NOT EXISTS ttl_seconds ON TABLE vault_versions TYPE option<int>;
            DEFINE FIELD IF NOT EXISTS auto_rotate ON TABLE vault_versions TYPE bool;
            DEFINE FIELD IF NOT EXISTS rotation_interval_days ON TABLE vault_versions TYPE option<int>;

            -- Updated indexes
            DEFINE INDEX IF NOT EXISTS vault_version_path_idx ON TABLE vault_versions COLUMNS path, version UNIQUE;
            DEFINE INDEX IF NOT EXISTS vault_version_workspace_idx ON TABLE vault_versions COLUMNS workspace_id;
            DEFINE INDEX IF NOT EXISTS vault_version_hierarchy_idx ON TABLE vault_versions COLUMNS workspace_id, infra_id, domain;
        "#).await?;

        self.db.query(r#"
            DEFINE TABLE IF NOT EXISTS vault_audit SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS secret_id ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS path ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS action ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS user_id ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS timestamp ON TABLE vault_audit TYPE datetime;
            DEFINE FIELD IF NOT EXISTS version ON TABLE vault_audit TYPE option<int>;
            DEFINE FIELD IF NOT EXISTS metadata ON TABLE vault_audit TYPE option<object>;

            -- NEW: Workspace isolation fields
            DEFINE FIELD IF NOT EXISTS workspace_id ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS domain ON TABLE vault_audit TYPE string;
            DEFINE FIELD IF NOT EXISTS secret_type ON TABLE vault_audit TYPE string;

            -- Updated indexes with workspace isolation
            DEFINE INDEX IF NOT EXISTS vault_audit_path_idx ON TABLE vault_audit COLUMNS path;
            DEFINE INDEX IF NOT EXISTS vault_audit_user_idx ON TABLE vault_audit COLUMNS user_id;
            DEFINE INDEX IF NOT EXISTS vault_audit_timestamp_idx ON TABLE vault_audit COLUMNS timestamp;
            DEFINE INDEX IF NOT EXISTS vault_audit_workspace_idx ON TABLE vault_audit COLUMNS workspace_id;
            DEFINE INDEX IF NOT EXISTS vault_audit_action_user_idx ON TABLE vault_audit COLUMNS action, user_id, timestamp;
        "#).await?;

        debug!("Initialized SurrealDB schema (including vault tables)");
        Ok(())
    }
}

// Shared methods for all connection types
impl<T> SurrealDbPolicyStorage<T>
where
    T: surrealdb::Connection,
{
    /// Generate record ID for table
    fn generate_record_id(&self, table: &str) -> RecordId {
        RecordId::new(table, Uuid::new_v4().to_string())
    }
}

impl SurrealDbPolicyStorage<surrealdb::engine::local::Db> {
    /// Create new in-memory SurrealDB storage for testing
    pub async fn new_memory(_config: &Config) -> Result<Self> {
        let db = Surreal::new::<Mem>(()).await?;

        db.use_ns("control_center").use_db("policies").await?;

        let storage = Self {
            db,
            namespace: "control_center".to_string(),
            database: "policies".to_string(),
        };

        storage.initialize_schema().await?;

        info!("Created in-memory SurrealDB storage");
        Ok(storage)
    }

    /// Initialize database schema
    async fn initialize_schema(&self) -> Result<()> {
        // Create tables with proper schemas
        self.db
            .query(
                r#"
            DEFINE TABLE IF NOT EXISTS policies SCHEMAFULL;
            DEFINE FIELD IF NOT EXISTS policy_id ON TABLE policies TYPE string;
            DEFINE FIELD IF NOT EXISTS content ON TABLE policies TYPE string;
            DEFINE FIELD IF NOT EXISTS metadata ON TABLE policies TYPE object;
            DEFINE FIELD IF NOT EXISTS created_at ON TABLE policies TYPE datetime;
            DEFINE FIELD IF NOT EXISTS updated_at ON TABLE policies TYPE datetime;
        "#,
            )
            .await?;

        Ok(())
    }
}

#[async_trait]
impl<T> PolicyStorage for SurrealDbPolicyStorage<T>
where
    T: surrealdb::Connection + Send + Sync,
{
    async fn store_policy(&self, id: &str, content: &str, metadata: &PolicyMetadata) -> Result<()> {
        let record = PolicyRecord {
            id: self.generate_record_id("policies"),
            policy_id: id.to_string(),
            content: content.to_string(),
            metadata: metadata.clone(),
            created_at: chrono::Utc::now(),
            updated_at: chrono::Utc::now(),
        };

        let _: Option<PolicyRecord> = self.db.create(("policies", id)).content(record).await?;
        debug!("Stored policy: {}", id);
        Ok(())
    }

    async fn get_policy(&self, id: &str) -> Result<String> {
        let record: Option<PolicyRecord> = self.db.select(("policies", id)).await?;
        match record {
            Some(record) => Ok(record.content),
            None => Err(ControlCenterError::Policy(policy::PolicyError::Evaluation(
                format!("Policy not found: {}", id),
            ))),
        }
    }

    async fn get_policy_metadata(&self, id: &str) -> Result<PolicyMetadata> {
        let record: Option<PolicyRecord> = self.db.select(("policies", id)).await?;
        match record {
            Some(record) => Ok(record.metadata),
            None => Err(ControlCenterError::Policy(policy::PolicyError::Evaluation(
                format!("Policy not found: {}", id),
            ))),
        }
    }

    async fn list_policies(&self) -> Result<Vec<PolicyMetadata>> {
        let records: Vec<PolicyRecord> = self.db.select("policies").await?;
        Ok(records.into_iter().map(|r| r.metadata).collect())
    }

    async fn delete_policy(&self, id: &str) -> Result<()> {
        let _: Option<PolicyRecord> = self.db.delete(("policies", id)).await?;
        debug!("Deleted policy: {}", id);
        Ok(())
    }

    async fn update_policy_metadata(&self, id: &str, metadata: &PolicyMetadata) -> Result<()> {
        let update_data = serde_json::json!({
            "metadata": metadata,
            "updated_at": chrono::Utc::now(),
        });

        let _: Option<PolicyRecord> = self.db.update(("policies", id)).merge(update_data).await?;
        debug!("Updated policy metadata: {}", id);
        Ok(())
    }

    async fn search_policies(&self, query: &PolicySearchQuery) -> Result<Vec<PolicyMetadata>> {
        let mut sql_query = String::from("SELECT * FROM policies WHERE 1=1");

        if query.enabled_only {
            sql_query.push_str(" AND metadata.enabled = true");
        }

        if let Some(category) = &query.category {
            sql_query.push_str(&format!(" AND metadata.category = '{}'", category));
        }

        if !query.tags.is_empty() {
            let tags_condition = query
                .tags
                .iter()
                .map(|tag| format!("'{}' IN metadata.tags", tag))
                .collect::<Vec<_>>()
                .join(" OR ");
            sql_query.push_str(&format!(" AND ({})", tags_condition));
        }

        if let Some(after) = query.created_after {
            sql_query.push_str(&format!(" AND created_at > '{}'", after.to_rfc3339()));
        }

        if let Some(before) = query.created_before {
            sql_query.push_str(&format!(" AND created_at < '{}'", before.to_rfc3339()));
        }

        sql_query.push_str(&format!(" LIMIT {} START {}", query.limit, query.offset));

        let mut response = self.db.query(&sql_query).await?;
        let records: Vec<PolicyRecord> = response.take(0)?;

        Ok(records.into_iter().map(|r| r.metadata).collect())
    }

    async fn store_policy_version(&self, version: &PolicyVersion) -> Result<()> {
        let record = PolicyVersionRecord {
            id: self.generate_record_id("policy_versions"),
            version: version.clone(),
        };

        let _: Option<PolicyVersionRecord> =
            self.db.create("policy_versions").content(record).await?;
        debug!(
            "Stored policy version: {} v{}",
            version.policy_id, version.version_number
        );
        Ok(())
    }

    async fn get_policy_version(
        &self,
        policy_id: &str,
        version_number: u32,
    ) -> Result<Option<PolicyVersion>> {
        let query = format!(
            "SELECT * FROM policy_versions WHERE version.policy_id = '{}' AND \
             version.version_number = {}",
            policy_id, version_number
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<PolicyVersionRecord> = response.take(0)?;

        Ok(records.into_iter().next().map(|r| r.version))
    }

    async fn get_current_policy_version(&self, policy_id: &str) -> Result<Option<PolicyVersion>> {
        let query = format!(
            "SELECT * FROM policy_versions WHERE version.policy_id = '{}' AND version.is_active = \
             true",
            policy_id
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<PolicyVersionRecord> = response.take(0)?;

        Ok(records.into_iter().next().map(|r| r.version))
    }

    async fn list_policy_versions(&self, policy_id: &str) -> Result<Vec<PolicyVersion>> {
        let query = format!(
            "SELECT * FROM policy_versions WHERE version.policy_id = '{}' ORDER BY \
             version.version_number DESC",
            policy_id
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<PolicyVersionRecord> = response.take(0)?;

        Ok(records.into_iter().map(|r| r.version).collect())
    }

    async fn deactivate_policy_version(&self, version_id: &str) -> Result<()> {
        let query = format!(
            "UPDATE policy_versions SET version.is_active = false WHERE version.version_id = '{}'",
            version_id
        );

        self.db.query(&query).await?;
        debug!("Deactivated policy version: {}", version_id);
        Ok(())
    }

    async fn delete_policy_version(&self, version_id: &str) -> Result<()> {
        let query = format!(
            "DELETE FROM policy_versions WHERE version.version_id = '{}'",
            version_id
        );

        self.db.query(&query).await?;
        debug!("Deleted policy version: {}", version_id);
        Ok(())
    }

    async fn tag_policy_version(
        &self,
        policy_id: &str,
        version_number: u32,
        tag: &str,
    ) -> Result<()> {
        let query = format!(
            "UPDATE policy_versions SET version.tags += '{}' WHERE version.policy_id = '{}' AND \
             version.version_number = {}",
            tag, policy_id, version_number
        );

        self.db.query(&query).await?;
        debug!(
            "Tagged policy version: {} v{} with tag: {}",
            policy_id, version_number, tag
        );
        Ok(())
    }

    async fn get_policy_versions_by_tag(
        &self,
        policy_id: &str,
        tag: &str,
    ) -> Result<Vec<PolicyVersion>> {
        let query = format!(
            "SELECT * FROM policy_versions WHERE version.policy_id = '{}' AND '{}' IN version.tags",
            policy_id, tag
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<PolicyVersionRecord> = response.take(0)?;

        Ok(records.into_iter().map(|r| r.version).collect())
    }

    async fn record_rollback_operation(
        &self,
        policy_id: &str,
        rollback: &RollbackResult,
    ) -> Result<()> {
        let record_data = serde_json::json!({
            "policy_id": policy_id,
            "rollback": rollback,
        });

        let _: Option<serde_json::Value> = self
            .db
            .create("rollback_operations")
            .content(record_data)
            .await?;
        debug!("Recorded rollback operation for policy: {}", policy_id);
        Ok(())
    }

    async fn store_policy_evaluation(&self, evaluation: &PolicyEvaluationEvent) -> Result<()> {
        let record = PolicyEvaluationRecord {
            id: self.generate_record_id("policy_evaluations"),
            evaluation: evaluation.clone(),
        };

        let _: Option<PolicyEvaluationRecord> =
            self.db.create("policy_evaluations").content(record).await?;
        debug!("Stored policy evaluation: {}", evaluation.id);
        Ok(())
    }

    async fn get_policy_evaluations(
        &self,
        policy_id: Option<&str>,
        limit: usize,
    ) -> Result<Vec<PolicyEvaluationEvent>> {
        let query = if let Some(pid) = policy_id {
            format!(
                "SELECT * FROM policy_evaluations WHERE evaluation.policy_id = '{}' ORDER BY \
                 evaluation.timestamp DESC LIMIT {}",
                pid, limit
            )
        } else {
            format!(
                "SELECT * FROM policy_evaluations ORDER BY evaluation.timestamp DESC LIMIT {}",
                limit
            )
        };

        let mut response = self.db.query(&query).await?;
        let records: Vec<PolicyEvaluationRecord> = response.take(0)?;

        Ok(records.into_iter().map(|r| r.evaluation).collect())
    }

    async fn get_policy_metrics(&self, policy_id: &str) -> Result<PolicyMetrics> {
        let query = format!(
            r#"
            SELECT
                count() as total_evaluations,
                math::sum(evaluation.execution_time_ms) as total_execution_time,
                math::mean(evaluation.execution_time_ms) as average_execution_time_ms,
                math::sum(CASE WHEN evaluation.decision = 'Allow' THEN 1 ELSE 0 END) as allow_decisions,
                math::sum(CASE WHEN evaluation.decision = 'Deny' THEN 1 ELSE 0 END) as deny_decisions,
                math::sum(array::len(evaluation.errors)) as error_count,
                math::max(evaluation.timestamp) as last_evaluation,
                math::min(evaluation.timestamp) as period_start,
                math::max(evaluation.timestamp) as period_end
            FROM policy_evaluations WHERE evaluation.policy_id = '{}'
            "#,
            policy_id
        );

        let mut response = self.db.query(&query).await?;
        let result: Vec<serde_json::Value> = response.take(0)?;

        if let Some(row) = result.first() {
            Ok(PolicyMetrics {
                policy_id: policy_id.to_string(),
                total_evaluations: row["total_evaluations"].as_u64().unwrap_or(0),
                allow_decisions: row["allow_decisions"].as_u64().unwrap_or(0),
                deny_decisions: row["deny_decisions"].as_u64().unwrap_or(0),
                average_execution_time_ms: row["average_execution_time_ms"].as_f64().unwrap_or(0.0),
                error_count: row["error_count"].as_u64().unwrap_or(0),
                last_evaluation: row["last_evaluation"]
                    .as_str()
                    .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
                    .map(|dt| dt.with_timezone(&chrono::Utc)),
                period_start: row["period_start"]
                    .as_str()
                    .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
                    .map(|dt| dt.with_timezone(&chrono::Utc))
                    .unwrap_or_else(chrono::Utc::now),
                period_end: row["period_end"]
                    .as_str()
                    .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
                    .map(|dt| dt.with_timezone(&chrono::Utc))
                    .unwrap_or_else(chrono::Utc::now),
            })
        } else {
            Ok(PolicyMetrics {
                policy_id: policy_id.to_string(),
                total_evaluations: 0,
                allow_decisions: 0,
                deny_decisions: 0,
                average_execution_time_ms: 0.0,
                error_count: 0,
                last_evaluation: None,
                period_start: chrono::Utc::now(),
                period_end: chrono::Utc::now(),
            })
        }
    }

    async fn store_compliance_check(&self, result: &ComplianceCheckResult) -> Result<()> {
        let record = ComplianceCheckRecord {
            id: self.generate_record_id("compliance_checks"),
            result: result.clone(),
        };

        let _: Option<ComplianceCheckRecord> =
            self.db.create("compliance_checks").content(record).await?;
        debug!("Stored compliance check result: {}", result.id);
        Ok(())
    }

    async fn get_compliance_history(
        &self,
        framework: Option<&str>,
    ) -> Result<Vec<ComplianceCheckResult>> {
        let query = if let Some(fw) = framework {
            format!(
                "SELECT * FROM compliance_checks WHERE result.framework = '{}' ORDER BY \
                 result.timestamp DESC",
                fw
            )
        } else {
            "SELECT * FROM compliance_checks ORDER BY result.timestamp DESC".to_string()
        };

        let mut response = self.db.query(&query).await?;
        let records: Vec<ComplianceCheckRecord> = response.take(0)?;

        Ok(records.into_iter().map(|r| r.result).collect())
    }
}

// Vault Secrets Management Implementation
use crate::services::secrets::VaultSecret;

impl<T> SurrealDbPolicyStorage<T>
where
    T: surrealdb::Connection + Send + Sync,
{
    /// Create a new vault secret
    pub async fn create_secret(&self, secret: &VaultSecret) -> Result<()> {
        let _: Option<VaultSecret> = self
            .db
            .create(("vault_secrets", secret.id.as_str()))
            .content(secret.clone())
            .await?;

        // Store initial version
        self.store_secret_version(secret).await?;

        debug!(
            "Created vault secret: {} at path: {}",
            secret.id, secret.path
        );
        Ok(())
    }

    /// Get a vault secret by path (current version)
    pub async fn get_secret_by_path(&self, path: &str) -> Result<Option<VaultSecret>> {
        let query = format!(
            "SELECT * FROM vault_secrets WHERE path = '{}' AND deleted = false",
            path
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<VaultSecret> = response.take(0)?;
        Ok(records.into_iter().next())
    }

    /// Get a specific version of a vault secret
    pub async fn get_secret_version(
        &self,
        path: &str,
        version: i32,
    ) -> Result<Option<VaultSecret>> {
        let query = format!(
            "SELECT * FROM vault_versions WHERE path = '{}' AND version = {}",
            path, version
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<serde_json::Value> = response.take(0)?;

        if let Some(record) = records.first() {
            // Helper to safely extract string arrays
            let extract_tags = |val: &serde_json::Value| -> Vec<String> {
                val.as_array()
                    .map(|arr| {
                        arr.iter()
                            .filter_map(|v| v.as_str().map(|s| s.to_string()))
                            .collect()
                    })
                    .unwrap_or_default()
            };

            // Helper to parse SecretType from string (for backward compatibility)
            let parse_secret_type = |type_str: Option<&str>| -> SecretType {
                match type_str {
                    Some("database") => SecretType::Database {
                        db_type: "unknown".to_string(),
                        connection_info: None,
                    },
                    Some("application") => SecretType::Application {
                        app_name: "unknown".to_string(),
                        key_type: "unknown".to_string(),
                    },
                    Some("ssh") => SecretType::SSH {
                        key_pair_id: "unknown".to_string(),
                        purpose: "unknown".to_string(),
                    },
                    Some("provider") => SecretType::Provider {
                        provider_name: "unknown".to_string(),
                        credential_type: "unknown".to_string(),
                    },
                    _ => SecretType::Application {
                        app_name: "unknown".to_string(),
                        key_type: "unknown".to_string(),
                    },
                }
            };

            let secret = VaultSecret {
                id: record["secret_id"].as_str().unwrap_or("").to_string(),
                path: record["path"].as_str().unwrap_or("").to_string(),
                encrypted_value: record["encrypted_value"].as_str().unwrap_or("").to_string(),
                version: record["version"].as_i64().unwrap_or(0) as i32,
                created_at: record["created_at"].as_str().unwrap_or("").to_string(),
                updated_at: record["updated_at"]
                    .as_str()
                    .unwrap_or_else(|| record["created_at"].as_str().unwrap_or(""))
                    .to_string(),
                created_by: record["created_by"].as_str().unwrap_or("").to_string(),
                updated_by: record["updated_by"]
                    .as_str()
                    .unwrap_or_else(|| record["created_by"].as_str().unwrap_or(""))
                    .to_string(),
                deleted: record["deleted"].as_bool().unwrap_or(false),
                encryption_context: record["encryption_context"].as_str().map(|s| s.to_string()),
                metadata: record["metadata"]
                    .as_object()
                    .map(|v| serde_json::Value::Object(v.clone())),
                workspace_id: record["workspace_id"]
                    .as_str()
                    .unwrap_or("default")
                    .to_string(),
                infra_id: record["infra_id"].as_str().map(|s| s.to_string()),
                domain: record["domain"].as_str().unwrap_or("unknown").to_string(),
                secret_type: parse_secret_type(record["secret_type"].as_str()),
                tags: extract_tags(&record["tags"]),
                ttl_seconds: record["ttl_seconds"].as_i64(),
                auto_rotate: record["auto_rotate"].as_bool().unwrap_or(false),
                rotation_interval_days: record["rotation_interval_days"].as_i64().map(|i| i as i32),
            };
            Ok(Some(secret))
        } else {
            Ok(None)
        }
    }

    /// List vault secrets with optional prefix filter
    pub async fn list_secrets(
        &self,
        prefix: Option<&str>,
        limit: usize,
        offset: usize,
    ) -> Result<(Vec<VaultSecret>, usize)> {
        let query = if let Some(pfx) = prefix {
            format!(
                "SELECT * FROM vault_secrets WHERE deleted = false AND path CONTAINS '{}' ORDER \
                 BY path ASC LIMIT {} START {}",
                pfx, limit, offset
            )
        } else {
            format!(
                "SELECT * FROM vault_secrets WHERE deleted = false ORDER BY path ASC LIMIT {} \
                 START {}",
                limit, offset
            )
        };

        let mut response = self.db.query(&query).await?;
        let records: Vec<VaultSecret> = response.take(0)?;

        // Get total count
        let count_query = if let Some(pfx) = prefix {
            format!(
                "SELECT count() FROM vault_secrets WHERE deleted = false AND path CONTAINS '{}'",
                pfx
            )
        } else {
            "SELECT count() FROM vault_secrets WHERE deleted = false".to_string()
        };

        let mut count_response = self.db.query(&count_query).await?;
        let count_records: Vec<serde_json::Value> = count_response.take(0)?;
        let total = count_records
            .first()
            .and_then(|v| v["count"].as_u64())
            .unwrap_or(0) as usize;

        Ok((records, total))
    }

    /// Update a vault secret (creates new version)
    pub async fn update_secret(&self, secret: &VaultSecret) -> Result<()> {
        // Update current version in vault_secrets
        let _: Option<VaultSecret> = self
            .db
            .update(("vault_secrets", secret.id.as_str()))
            .content(secret.clone())
            .await?;

        // Store new version
        self.store_secret_version(secret).await?;

        debug!(
            "Updated vault secret: {} to version {}",
            secret.id, secret.version
        );
        Ok(())
    }

    /// Soft delete a vault secret
    pub async fn delete_secret(&self, secret_id: &str) -> Result<()> {
        let update_data = serde_json::json!({
            "deleted": true,
            "updated_at": chrono::Utc::now().to_rfc3339(),
        })
        .to_string();

        let _: Option<VaultSecret> = self
            .db
            .update(("vault_secrets", secret_id))
            .merge(serde_json::from_str::<serde_json::Value>(&update_data).unwrap())
            .await?;

        debug!("Deleted vault secret: {}", secret_id);
        Ok(())
    }

    /// Store a version of a vault secret
    async fn store_secret_version(&self, secret: &VaultSecret) -> Result<()> {
        let version_data = serde_json::json!({
            "secret_id": &secret.id,
            "path": &secret.path,
            "encrypted_value": &secret.encrypted_value,
            "version": secret.version,
            "created_at": &secret.updated_at,
            "created_by": &secret.updated_by,
            "encryption_context": &secret.encryption_context,
            "metadata": &secret.metadata,
        })
        .to_string();

        let parsed: serde_json::Value = serde_json::from_str(&version_data).unwrap();
        let _: Option<serde_json::Value> = self.db.create("vault_versions").content(parsed).await?;
        debug!(
            "Stored vault secret version: {} v{}",
            secret.path, secret.version
        );
        Ok(())
    }

    /// Get secret history (all versions)
    pub async fn get_secret_history(&self, path: &str) -> Result<Vec<VaultSecret>> {
        let query = format!(
            "SELECT * FROM vault_versions WHERE path = '{}' ORDER BY version DESC",
            path
        );

        let mut response = self.db.query(&query).await?;
        let records: Vec<serde_json::Value> = response.take(0)?;

        let secrets = records
            .into_iter()
            .map(|record| {
                // Helper to safely extract string arrays
                let extract_tags = |val: &serde_json::Value| -> Vec<String> {
                    val.as_array()
                        .map(|arr| {
                            arr.iter()
                                .filter_map(|v| v.as_str().map(|s| s.to_string()))
                                .collect()
                        })
                        .unwrap_or_default()
                };

                // Helper to parse SecretType from string
                let parse_secret_type = |type_str: Option<&str>| -> SecretType {
                    match type_str {
                        Some("database") => SecretType::Database {
                            db_type: "unknown".to_string(),
                            connection_info: None,
                        },
                        Some("application") => SecretType::Application {
                            app_name: "unknown".to_string(),
                            key_type: "unknown".to_string(),
                        },
                        Some("ssh") => SecretType::SSH {
                            key_pair_id: "unknown".to_string(),
                            purpose: "unknown".to_string(),
                        },
                        Some("provider") => SecretType::Provider {
                            provider_name: "unknown".to_string(),
                            credential_type: "unknown".to_string(),
                        },
                        _ => SecretType::Application {
                            app_name: "unknown".to_string(),
                            key_type: "unknown".to_string(),
                        },
                    }
                };

                VaultSecret {
                    id: record["secret_id"].as_str().unwrap_or("").to_string(),
                    path: record["path"].as_str().unwrap_or("").to_string(),
                    encrypted_value: record["encrypted_value"].as_str().unwrap_or("").to_string(),
                    version: record["version"].as_i64().unwrap_or(0) as i32,
                    created_at: record["created_at"].as_str().unwrap_or("").to_string(),
                    updated_at: record["updated_at"]
                        .as_str()
                        .unwrap_or_else(|| record["created_at"].as_str().unwrap_or(""))
                        .to_string(),
                    created_by: record["created_by"].as_str().unwrap_or("").to_string(),
                    updated_by: record["updated_by"]
                        .as_str()
                        .unwrap_or_else(|| record["created_by"].as_str().unwrap_or(""))
                        .to_string(),
                    deleted: record["deleted"].as_bool().unwrap_or(false),
                    encryption_context: record["encryption_context"]
                        .as_str()
                        .map(|s| s.to_string()),
                    metadata: record["metadata"]
                        .as_object()
                        .map(|v| serde_json::Value::Object(v.clone())),
                    workspace_id: record["workspace_id"]
                        .as_str()
                        .unwrap_or("default")
                        .to_string(),
                    infra_id: record["infra_id"].as_str().map(|s| s.to_string()),
                    domain: record["domain"].as_str().unwrap_or("unknown").to_string(),
                    secret_type: parse_secret_type(record["secret_type"].as_str()),
                    tags: extract_tags(&record["tags"]),
                    ttl_seconds: record["ttl_seconds"].as_i64(),
                    auto_rotate: record["auto_rotate"].as_bool().unwrap_or(false),
                    rotation_interval_days: record["rotation_interval_days"]
                        .as_i64()
                        .map(|i| i as i32),
                }
            })
            .collect();

        Ok(secrets)
    }
}

// SurrealDB storage type alias for general use
pub type SurrealDbStorage = SurrealDbPolicyStorage;
