//! Standard DBMS procedures (dbms.*).

use crate::error::ExecutionResult;
use crate::graph::GraphBackend;
use crate::result::{CypherValue, Record};

use super::{Procedure, ProcedureContext, ProcedureInfo, ProcedureMode, YieldInfo};

/// dbms.procedures() - List all registered procedures.
///
/// Note: This is a special procedure that needs access to the registry itself.
/// For now, we'll return a minimal implementation that just returns itself.
/// A full implementation would require passing the registry to the procedure.
pub struct DbmsProcedures {
    /// Cached list of procedure metadata from the registry.
    procedures: Vec<ProcedureInfo>,
}

impl DbmsProcedures {
    /// Create a new dbms.procedures() with cached procedure list.
    pub fn new(procedures: Vec<ProcedureInfo>) -> Self {
        Self { procedures }
    }
}

impl<G: GraphBackend> Procedure<G> for DbmsProcedures {
    fn info(&self) -> ProcedureInfo {
        ProcedureInfo {
            name: "dbms.procedures".to_string(),
            description: "List all registered procedures".to_string(),
            mode: ProcedureMode::Dbms,
            parameters: vec![],
            yields: vec![
                YieldInfo {
                    name: "name".to_string(),
                    type_name: "STRING".to_string(),
                },
                YieldInfo {
                    name: "description".to_string(),
                    type_name: "STRING".to_string(),
                },
                YieldInfo {
                    name: "mode".to_string(),
                    type_name: "STRING".to_string(),
                },
            ],
        }
    }

    fn call(&self, _ctx: &ProcedureContext<G>) -> ExecutionResult<Vec<Record>> {
        let mut results = Vec::new();

        for proc_info in &self.procedures {
            let mut record = Record::new();
            record.add("name", CypherValue::String(proc_info.name.clone()));
            record.add("description", CypherValue::String(proc_info.description.clone()));
            record.add("mode", CypherValue::String(format!("{:?}", proc_info.mode)));
            results.push(record);
        }

        // Sort by name for consistent output
        results.sort_by(|a, b| {
            let name_a = a.get("name").and_then(|v| v.as_string()).unwrap_or("");
            let name_b = b.get("name").and_then(|v| v.as_string()).unwrap_or("");
            name_a.cmp(name_b)
        });

        Ok(results)
    }
}
