//! @docs ARCHITECTURE:Registry
//!
//! ### AI Assist Note
//! **Core technical resource for the Tadpole OS Sovereign infrastructure.**
//! This module implements high-fidelity logic for the Sovereign Reality layer.
//!
//! ### 🔍 Debugging & Observability
//! - **Failure Path**: Runtime logic error, state desynchronization, or resource exhaustion.
//! - **Telemetry Link**: Search `[mod]` in tracing logs.

pub mod context;
pub mod encoder;
pub mod fragments;
pub mod pruner;
pub mod toolbelt;

use crate::agent::constants::*;
use crate::agent::runner::synthesis::encoder::aaak_encode;
use crate::agent::runner::synthesis::fragments::*;
use crate::agent::runner::RunContext;
use crate::state::AppState;
use std::collections::HashMap;

pub struct PromptAssemblerContext<'a> {
    pub directives: &'a str,
    pub reviews: &'a str,
    pub identity: &'a str,
    pub memory: &'a str,
    pub repo_map: &'a str,
    pub swarm_context: &'a str,
    pub criticality_score: i32,
    pub failure_context: Vec<String>,
}

pub fn assemble_prompt_variables(
    ctx: &RunContext,
    state: &AppState,
    p_ctx: PromptAssemblerContext<'_>,
) -> HashMap<&'static str, String> {
    let hierarchy_label = get_hierarchy_label(ctx.authority_level);
    let compressed_swarm_context = aaak_encode(p_ctx.swarm_context);

    let priority_str = if ctx.agent_id == AGENT_CEO {
        "STRATEGIC OVERLORD: You are the final authority. Your priority is mission synthesis and high-level routing."
    } else if ctx.agent_id == AGENT_ALPHA {
        "ALPHA MISSION COMMANDER: Your priority is tactical execution and specialist coordination."
    } else {
        "TACTICAL SPECIALIST: Your priority is focused task completion."
    };

    let raw_findings = ctx
        .recent_findings
        .as_deref()
        .unwrap_or("No recent findings inherited.");
    let deduplicated_findings =
        crate::utils::deduplicator::SwarmDeduplicator::deduplicate_syntax(raw_findings);
    let compressed_findings = aaak_encode(&deduplicated_findings);
    let swarm_str = generate_swarm_protocols(ctx, state);

    let skill_fragments_str = generate_skill_fragments(ctx, state);
    let workflow_fragments_str = generate_workflow_fragments(ctx, state);

    let (
        cluster_directory,
        filesystem_bias_mandate,
        lineage_display,
        _is_orchestrator,
        safe_mode_prefix,
        tool_mode_prefix,
    ) = generate_structural_components(ctx, state);

    let mut vars = HashMap::new();
    vars.insert("name", ctx.name.clone());
    vars.insert("agent_id", ctx.agent_id.clone());
    vars.insert("role", ctx.role.clone());
    vars.insert("department", ctx.department.clone());
    vars.insert("description", ctx.description.clone());
    vars.insert("hierarchy_label", hierarchy_label.to_string());
    vars.insert("directives", p_ctx.directives.to_string());
    vars.insert("reviews", p_ctx.reviews.to_string());
    vars.insert("global_intelligence", "N/A (RAG-Enabled Swarm)".to_string());
    vars.insert("priority", priority_str.to_string());
    vars.insert(
        "personality",
        ctx.model_config
            .system_prompt
            .as_deref()
            .unwrap_or("No specific personality instructions.")
            .to_string(),
    );
    vars.insert("skill_fragments", skill_fragments_str.to_string());
    vars.insert("workflow_fragments", workflow_fragments_str.to_string());
    vars.insert("swarm_context", compressed_swarm_context.to_string());
    vars.insert("breadcrumbs", generate_breadcrumbs_display(ctx).to_string());
    vars.insert("findings", compressed_findings.to_string());
    vars.insert(
        "primary_goal",
        ctx.primary_goal
            .clone()
            .unwrap_or_else(|| "See mission scope for details.".to_string()),
    );
    vars.insert("cluster_directory", cluster_directory.to_string());
    vars.insert("lineage", lineage_display.to_string());
    vars.insert("skills", format!("{:?}", ctx.skills));
    vars.insert("workflows", format!("{:?}", ctx.workflows));
    vars.insert("filesystem_bias", filesystem_bias_mandate.to_string());
    vars.insert("swarm_protocols", swarm_str.to_string());
    vars.insert("repo_map", p_ctx.repo_map.to_string());
    vars.insert("identity", p_ctx.identity.to_string());

    let deduplicated_memory =
        crate::utils::deduplicator::SwarmDeduplicator::deduplicate_syntax(p_ctx.memory);
    vars.insert("memory", deduplicated_memory);

    vars.insert(
        "graph_context",
        ctx.graph_context.clone().unwrap_or_default(),
    );
    vars.insert(
        "working_memory",
        serde_json::to_string_pretty(&ctx.working_memory).unwrap_or_else(|_| "{}".to_string()),
    );

    let raw_history = ctx
        .summarized_history
        .as_deref()
        .unwrap_or("No history summarized yet.");
    let deduplicated_history =
        crate::utils::deduplicator::SwarmDeduplicator::deduplicate_syntax(raw_history);
    vars.insert("history", aaak_encode(&deduplicated_history).to_string());
    vars.insert("safe_mode_prefix", safe_mode_prefix.clone());
    vars.insert("tool_mode_prefix", tool_mode_prefix.to_string());

    if p_ctx.criticality_score > 0 {
        let warning = format!("\n\n!!! SYSTEM WARNING: Critical services failed (Score: {}/3) !!!\n- {}\n!!! ACTION: Acknowledge these failures in your internal reasoning and attempt to recover missing context manually if possible. !!!\n", p_ctx.criticality_score, p_ctx.failure_context.join("\n- "));
        vars.insert(
            "safe_mode_prefix",
            format!("{}{}", safe_mode_prefix, warning),
        );
    }

    vars
}

impl super::AgentRunner {
    /// 📟 [AAAK Encoder]
    #[allow(dead_code)]
    pub fn aaak_encode(&self, text: &str) -> String {
        self::encoder::aaak_encode(text)
    }

    /// Constructs the final system prompt for an agent run.
    pub async fn build_system_prompt(&self, ctx: &RunContext, payload_message: &str) -> String {
        let (directives_str, reviews_str) =
            self::context::fetch_external_context(ctx, &self.state).await;

        let _global_intel_str = match self::context::gather_global_intelligence(
            ctx,
            &self.state,
            payload_message,
        )
        .await
        {
            Ok(intel) => intel,
            Err(e) => {
                tracing::warn!("⚠️ [Global Intelligence] Vault search failed: {}.", e);
                "GLOBAL_INTEL_FAILURE: Knowledge vault was unreachable.".to_string()
            }
        };

        let mut criticality_score = 0;
        let mut failure_context = Vec::new();

        let identity = match self::context::fetch_identity(&self.state).await {
            Ok(id) => id,
            Err(e) => {
                criticality_score += 1;
                failure_context.push(format!(
                    "IDENTITY_FAILURE: Core identity directives could not be loaded: {}.",
                    e
                ));
                tracing::error!("🚨 [Runner] Identity lookup failed: {}.", e);
                String::new()
            }
        };

        let memory = match self::context::fetch_memory(&self.state).await {
            Ok(mem) => mem,
            Err(e) => {
                criticality_score += 1;
                failure_context.push(format!(
                    "MEMORY_FAILURE: Long-term memory context could not be retrieved: {}.",
                    e
                ));
                tracing::error!("🚨 [Runner] Memory lookup failed: {}.", e);
                String::new()
            }
        };

        let swarm_context_str = match self::context::fetch_mission_context(ctx, &self.state).await {
            Ok(context) => context,
            Err(e) => {
                criticality_score += 1;
                failure_context.push(format!(
                    "SWARM_CONTEXT_FAILURE: Failed to retrieve mission context: {:?}.",
                    e
                ));
                tracing::error!(
                    "🚨 [Runner] Failed to retrieve mission context for {}: {:?}.",
                    ctx.mission_id,
                    e
                );
                String::from("⚠️ WARNING: Failed to load shared mission context.")
            }
        };

        let (_repo_summary, repo_map_text) = self.generate_repo_map(ctx, payload_message).await;

        let (pruned_repo_map, pruned_swarm_context_str) = self::pruner::prune_context(
            ctx,
            &identity,
            &memory,
            &repo_map_text,
            &swarm_context_str,
        );

        let vars = assemble_prompt_variables(
            ctx,
            &self.state,
            PromptAssemblerContext {
                directives: &directives_str,
                reviews: &reviews_str,
                identity: &identity,
                memory: &memory,
                repo_map: &pruned_repo_map,
                swarm_context: &pruned_swarm_context_str,
                criticality_score,
                failure_context,
            },
        );

        let mut system_prompt = self.state.resources.renderer.render(
            self.state.resources.renderer.default_system_template(),
            &vars,
        );

        let role_lower = ctx.role.to_lowercase();
        let is_alpha_commander = ctx.depth <= 1
            && (role_lower.contains("alpha")
                || role_lower.contains("commander")
                || role_lower.contains("coo")
                || role_lower.contains("ceo")
                || ctx.agent_id == "1"
                || ctx.agent_id == "2");

        if is_alpha_commander {
            system_prompt.push_str("\n\n### 🛡️ SWARM COMMANDER DIRECTIVE (ALPHA OVERLAY)\n- DECOMPOSE & DELEGATE: Deconstruct mission objectives into single-responsibility sub-tasks for cluster workers.\n- FAN-IN COMPRESSION: Filter raw terminal logs. Summarize worker results into a 4-bullet digest (Completed, Verified, Artifact URIs, Blockers).\n- WORKER GUARD: Freeze any specialist node after 2 consecutive tool failures.\n");
        }

        system_prompt = self.shorten_system_tokens(&system_prompt);

        tracing::info!(
            "🏁 [Runner] Synthesizing system prompt for mission: {} (Depth: {})",
            ctx.mission_id,
            ctx.depth
        );
        system_prompt
    }

    /// Generates the Repo Map summary.
    pub async fn generate_repo_map(
        &self,
        ctx: &RunContext,
        payload_message: &str,
    ) -> (crate::utils::graph::GraphSummary, String) {
        let graph = self.state.resources.get_code_graph().await;
        let summary = graph.read().generate_summary();

        // Strictly check if the agent role, department, or prompt context requires codebase knowledge
        let is_technical_role = ctx.department.contains("Technical")
            || ctx.department.contains("Engineering")
            || ctx.department.contains("Quality Assurance")
            || ctx.role.to_lowercase().contains("cto")
            || ctx.role.to_lowercase().contains("developer")
            || ctx.role.to_lowercase().contains("engineer")
            || ctx.role.to_lowercase().contains("auditor");

        let msg_lower = payload_message.to_lowercase();
        let words: std::collections::HashSet<&str> = msg_lower
            .split(|c: char| !c.is_alphanumeric())
            .filter(|s| !s.is_empty())
            .collect();

        let contains_code_keywords = words.contains("code")
            || words.contains("file")
            || words.contains("files")
            || words.contains("rust")
            || words.contains("cargo")
            || words.contains("npm")
            || words.contains("compile")
            || words.contains("test")
            || words.contains("tests")
            || words.contains("git")
            || words.contains("github")
            || words.contains("build")
            || words.contains("architecture")
            || words.contains("bug")
            || words.contains("bugs")
            || words.contains("refactor")
            || words.contains("db")
            || words.contains("database")
            || words.contains("migration")
            || words.contains("migrations")
            || words.contains("route")
            || words.contains("routes")
            || words.contains("api")
            || words.contains("apis")
            || words.contains("endpoint")
            || words.contains("endpoints");

        let should_include_repo_map = (is_technical_role
            || (payload_message.len() > 10 && contains_code_keywords))
            && !ctx.safe_mode
            // Depth guard: sub-agents at depth ≥ 2 receive targeted context from their parent.
            // Injecting the full repo map compounds token usage exponentially per swarm level.
            && ctx.depth < 2;

        if should_include_repo_map {
            (summary.clone(), summary.text)
        } else {
            (
                crate::utils::graph::GraphSummary {
                    text: "Architecture Map: Omitted for non-technical task to save tokens and prevent local CPU latency.".to_string(),
                    hot_paths: vec![],
                },
                "Architecture Map: Omitted for non-technical task to save tokens and prevent local CPU latency.".to_string(),
            )
        }
    }

    /// Manifests the agent's toolbelt.
    pub async fn build_tools(&self, ctx: &RunContext) -> crate::agent::types::ToolDefinition {
        self::toolbelt::build_tools(ctx, &self.state).await
    }

    /// Compresses common verbose status strings in system prompts to save tokens.
    pub fn shorten_system_tokens(&self, text: &str) -> String {
        text.replace("STATUS: ok", "*ok*")
            .replace("STATUS: failed", "*err*")
            .replace("STATUS: completed", "*done*")
            .replace("FINDING:", "FND:")
            .replace("OBJECTIVE:", "OBJ:")
            .replace("TOOL_CALL:", "TC:")
            .replace("RESULT:", "RES:")
    }
}

fn generate_breadcrumbs_display(ctx: &RunContext) -> String {
    let breadcrumbs = ctx.last_accessed_files.lock();
    if breadcrumbs.is_empty() {
        "None available.".to_string()
    } else {
        breadcrumbs.join("\n- ")
    }
}

// Metadata: [mod]

#[cfg(test)]
mod tests {

    use crate::agent::runner::{AgentRunner, RunContext};
    use crate::state::AppState;
    use std::sync::Arc;

    #[tokio::test]
    async fn test_generate_repo_map_heuristics() {
        let state = Arc::new(AppState::new_minimal_mock().await);
        let runner = AgentRunner::new(state);

        // 1. Non-technical agent, non-technical query -> Omitted
        let mut ctx = RunContext::default();
        ctx.department = "Executive".to_string();
        ctx.role = "CEO".to_string();
        let (summary, text) = runner
            .generate_repo_map(&ctx, "3 day weather in zipcode 19702")
            .await;
        assert!(text.contains("Omitted for non-technical task"));
        assert!(summary.text.contains("Omitted for non-technical task"));

        // 2. Technical agent (Engineering department) -> Included
        ctx.department = "Engineering".to_string();
        let (summary2, text2) = runner.generate_repo_map(&ctx, "weather").await;
        assert!(!text2.contains("Omitted for non-technical task"));
        assert!(!summary2.text.contains("Omitted for non-technical task"));

        // 3. Non-technical agent, but query contains technical keywords -> Included
        ctx.department = "Executive".to_string();
        ctx.role = "CEO".to_string();
        let (summary3, text3) = runner
            .generate_repo_map(&ctx, "fix a bug in rust files")
            .await;
        assert!(!text3.contains("Omitted for non-technical task"));
        assert!(!summary3.text.contains("Omitted for non-technical task"));
    }
}
