use mimirs_core::{
    AgentId, BlockId, ConsolidationReport, DensityMemory, Memory, MemoryAgent, MemoryBlock,
    MemoryId, MemoryInput, MemorySnapshot, MimirError, QuantumMeasurementResult, RecallQuery,
};
use mimirs_forget::{ConsolidationConfig, Muninn};
use mimirs_ha::{EventBus, MemorySignal, Saga, SagaEntry, ThingNode};
use mimirs_identity::IdentityKnot;
use mimirs_oracle::{Forseti, Ginnunga};
use mimirs_otoc::Vafthrudnir;
use mimirs_reservoir::Hugin;
use mimirs_sleeptime::Nott;
use mimirs_store::Urdarbrunnr;
use mimirs_yggdrasil::{ManifoldIndex, Yggdrasil};
use std::sync::Arc;
use std::sync::Mutex as StdMutex;
use tokio::sync::Mutex as TokioMutex;

/// Main agent facade combining all subsystems (L1-L7).
#[allow(dead_code)]
pub struct MimirAgent {
    well: Arc<Urdarbrunnr>,
    hugin: StdMutex<Hugin>,
    muninn: StdMutex<Muninn>,
    vafthrudnir: StdMutex<Vafthrudnir>,
    forseti: Forseti,
    ginnunga: Ginnunga,
    saga: StdMutex<Saga>,
    thing: TokioMutex<ThingNode>,
    bus: EventBus,
    nott: Option<Nott>,
    yggdrasil: Yggdrasil,
    identity: StdMutex<IdentityKnot>,
    /// Unified embedding backend — always present, auto-selects best available.
    embedding: mimirs_encoding::EmbeddingBackend,
    quorum: Arc<mimirs_ha::ElderQuorum>,
    manifold_dim: usize,
    session_id: String,
    bridge_handles: Option<Vec<tokio::task::JoinHandle<()>>>,
}

impl MimirAgent {
    /// Creates a new MimirAgent with default Phase 6 components (L1-L7).
    pub fn new(well: Arc<Urdarbrunnr>, config: crate::config::AgentConfig) -> Self {
        let agent_id = AgentId::from_uuid(
            uuid::Uuid::parse_str(&config.agent_id).unwrap_or_else(|_| uuid::Uuid::new_v4()),
        );
        let bus = EventBus::new();
        let quorum = Arc::new(mimirs_ha::ElderQuorum::new());

        let session_id = config
            .session_id
            .clone()
            .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());

        // Initialize embedding backend — auto-selects best available
        let model_path = std::path::PathBuf::from(
            std::env::var("MIMIRS_MODEL_PATH")
                .unwrap_or_else(|_| config.model_path.clone()),
        );
        let embedding = mimirs_encoding::EmbeddingBackend::auto(&model_path, config.manifold_dim);

        // Clone values needed by the bridge task before they're moved into the struct
        let well_for_bridge = well.clone();
        let session_for_bridge = session_id.clone();

        let mut agent = Self {
            well,
            hugin: StdMutex::new(Hugin::new(config.decay_rate, config.coherence_threshold)),
            muninn: StdMutex::new(Muninn::new(ConsolidationConfig {
                collapse_threshold: config.coherence_threshold,
                ewc_lambda: 1.0,
            })),
            vafthrudnir: StdMutex::new(Vafthrudnir::new()),
            forseti: Forseti::new(),
            ginnunga: Ginnunga::new(config.contradiction_threshold),
            saga: StdMutex::new(Saga::new()),
            thing: TokioMutex::new(ThingNode::new(agent_id, bus.clone())),
            bus,
            nott: None,
            yggdrasil: Yggdrasil::new(agent_id),
            identity: StdMutex::new(IdentityKnot::new(
                mimirs_core::DensityMemory::from_pure(&{
                    let mut v = vec![0.0f32; 128];
                    v[0] = 1.0;
                    v
                })
                .unwrap()),
            ),
            embedding,
            quorum,
            manifold_dim: config.manifold_dim,
            session_id,
            bridge_handles: None,
        };

        // Spawn multi-agent bridge receiver if HA is enabled
        let bridge_handles = if config.ha_enabled {
            let mut handles = Vec::new();
            let recv_handle = tokio::spawn(async move {
                let nats_url = std::env::var("MIMIRS_NATS_URL")
                    .unwrap_or_else(|_| "nats://localhost:4222".to_string());

                match async_nats::connect(&nats_url).await {
                    Ok(nats_client) => {
                        tracing::info!(
                            session = %session_for_bridge,
                            nats_url = %nats_url,
                            "Multi-agent bridge connected to NATS"
                        );
                        let subject = format!(
                            "MIMIRS.SIGNAL.{}",
                            session_for_bridge.to_uppercase().replace('-', "_")
                        );
                        match nats_client.subscribe(subject.clone()).await {
                            Ok(mut sub) => {
                                tracing::info!(subject = %subject, "Bridge inbound listener active");
                                loop {
                                    match futures::StreamExt::next(&mut sub).await {
                                        Some(msg) => {
                                            if let Ok(signal) = serde_json::from_slice::<mimirs_ha::MemorySignal>(&msg.payload) {
                                                tracing::debug!(?signal, "Received remote bridge signal");
                                                if let mimirs_ha::MemorySignal::MemoryStored { agent_id, .. } = &signal {
                                                    let remote_mem = mimirs_core::Memory {
                                                        id: mimirs_core::MemoryId::new(),
                                                        content: format!("Remote memory from agent {}", agent_id),
                                                        metadata: Default::default(),
                                                        scope: mimirs_core::MemoryScope::Agent,
                                                        verifiability: mimirs_core::VerifiabilityStage::Speculative,
                                                        memory_class: mimirs_core::MemoryClass::Semantic,
                                                        rho: None,
                                                        qrc_state: None,
                                                        scramble_score: None,
                                                        source_session: Some(agent_id.to_string()),
                                                    };
                                                    if let Err(e) = well_for_bridge.rista(&remote_mem) {
                                                        tracing::warn!(error = %e, "Failed to store remote memory");
                                                    }
                                                }
                                            }
                                        }
                                        None => break,
                                    }
                                }
                            }
                            Err(e) => {
                                tracing::warn!(error = %e, subject = %subject, "Bridge inbound subscribe failed");
                            }
                        }
                    }
                    Err(e) => {
                        tracing::warn!(error = %e, nats_url = %nats_url, "NATS connection failed — bridge in standalone mode");
                    }
                }
            });
            handles.push(recv_handle);
            Some(handles)
        } else {
            None
        };

        agent.bridge_handles = bridge_handles;
        agent
    }

    /// Returns the name of the active embedding backend.
    pub fn embedding_backend(&self) -> &'static str {
        self.embedding.backend_name()
    }

    /// Returns true if using real inference (not dummy).
    pub fn has_real_embedding(&self) -> bool {
        self.embedding.is_real()
    }

    /// Returns the current session ID.
    pub fn session_id(&self) -> &str {
        &self.session_id
    }

    /// Sets the Nott reflection engine with a weak reference to the agent.
    pub fn set_nott(&mut self, nott: Nott) {
        self.nott = Some(nott);
    }

    /// Returns the current identity depth (Ollivier-Ricci Curvature).
    pub async fn identity_depth(&self) -> Result<f32, MimirError> {
        let query = RecallQuery::new("").with_limit(500);
        let memories = self.well.minni(query).await?;
        let pool: Vec<_> = memories
            .into_iter()
            .map(|m| (m.id, m.memory.clone()))
            .collect();
        let index = ManifoldIndex::build(&pool)?;
        Ok(index.identity_depth())
    }

    /// Synchronizes ethical anchors from the topological manifold.
    pub async fn sync_identity_anchors(
        &mut self,
        memories: &[(MemoryId, DensityMemory)],
    ) -> Result<(), MimirError> {
        let index = ManifoldIndex::build(memories)?;
        self.identity.lock().unwrap().sync_anchors(&index, memories)
    }

    /// Performs recursive stabilization on the identity knot.
    pub async fn stabilize_identity(&mut self, alpha: f32) -> Result<(), MimirError> {
        self.identity.lock().unwrap().stabilize(alpha)
    }

    /// Returns a reference to the event bus.
    pub fn bus(&self) -> &EventBus {
        &self.bus
    }

    /// Prunes WaveField modes.
    pub fn prune_hologram(&self, threshold: std::time::Duration) -> Result<usize, MimirError> {
        self.well.prune_hologram(threshold)
    }
}

// Phase 2 implementation
#[async_trait::async_trait]
impl MemoryAgent for MimirAgent {
    async fn store(&self, entry: MemoryInput) -> Result<MemoryId, MimirError> {
        let id = MemoryId::new();
        let span = tracing::info_span!("rista", memory_id = %id, class = ?entry.memory_class);
        let _enter = span.enter();

        // Generate Density Matrix (Q1) via unified embedding backend
        let rho = if entry.content.is_empty() {
            None
        } else {
            match self.embedding.embed_to_density(&entry.content) {
                Ok(rho) => {
                    tracing::debug!(backend = %self.embedding.backend_name(), dim = rho.dimension(), "Embedding generated");
                    Some(rho)
                }
                Err(e) => {
                    tracing::error!(error = %e, "All embedding backends failed for store");
                    None
                }
            }
        };

        // Register Activity
        if let Ok(mut hugin) = self.hugin.lock() {
            hugin.register_activity(id, 0.5);
        }

        // Use session ID as source if none provided
        let source = entry.source_session.clone()
            .unwrap_or_else(|| self.session_id.clone());

        let memory = Memory {
            id,
            content: entry.content,
            metadata: entry.metadata.unwrap_or_default(),
            scope: entry.scope.unwrap_or_default(),
            verifiability: entry.verifiability.unwrap_or_default(),
            memory_class: entry.memory_class.unwrap_or_default(),
            rho,
            qrc_state: None,
            scramble_score: None,
            source_session: Some(source),
        };

        self.well.rista(&memory)?;

        // Record Initial Gradient for OTOC
        if let Some(ref rho) = memory.rho {
            if let Ok(mut vaf) = self.vafthrudnir.lock() {
                let diag = rho.diagonal();
                let _ = vaf.record_gradient(&id.to_string(), &diag.to_vec());
            }
            // Push to Generative Replay Buffer
            if let Ok(mut mun) = self.muninn.lock() {
                mun.push_to_replay(rho);
            }
            // Reinforce pattern in identity
            if let Err(e) = self.identity.lock().unwrap().reinforce_pattern(rho) {
                tracing::warn!(error = %e, "Pattern reinforcement failed");
            }
        }

        if let Err(e) = self.bus.broadcast(MemorySignal::MemoryStored {
            agent_id: self.yggdrasil.identity.id,
            memory_id: id,
            memory_class: memory.memory_class,
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for MemoryStored");
        }

        tracing::info!(status = "success", "Memory carved");
        Ok(id)
    }

    async fn recall(
        &self,
        query: RecallQuery,
    ) -> Result<Vec<QuantumMeasurementResult>, MimirError> {
        let span = tracing::info_span!("minni", query = %query.query, limit = query.limit);
        let _enter = span.enter();

        // Vectorize query via unified embedding backend
        let mut query = query;
        if let Ok(q_rho) = self.embedding.embed_to_density(&query.query) {
            query = query.with_query_rho(q_rho);
        }

        tracing::debug!("Recalling from Urdarbrunnr");
        let results = self.well.minni(query.clone()).await?;

        if let Err(e) = self.bus.broadcast(MemorySignal::MemoryRecalled {
            agent_id: self.yggdrasil.identity.id,
            query: query.query.clone(),
            results_count: results.len(),
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for MemoryRecalled");
        }

        if let Ok(mut hugin) = self.hugin.lock() {
            for res in results.iter() {
                hugin.register_activity(res.id, 0.2);
            }
        }

        tracing::info!(results_count = results.len(), "Recall complete");
        Ok(results)
    }

    async fn forget(&self, id: MemoryId) -> Result<(), MimirError> {
        tracing::info!(memory_id = %id, "Forgetting memory (tombstoning)");

        if let Ok(vaf) = self.vafthrudnir.lock()
            && let Err(mimirs_otoc::OtocError::MemoryLoadBearing { score, .. }) =
                vaf.is_safe_to_forget(&id.to_string(), 0.7)
        {
            return Err(MimirError::MemoryLoadBearing {
                score: score.0,
                threshold: 0.7,
            });
        }

        self.well.eyda(id)
    }

    async fn monitor_criticality(&self) -> Result<f32, MimirError> {
        let query = RecallQuery::new("").with_limit(100);
        let results = self.well.minni(query).await?;
        if results.is_empty() {
            return Ok(1.0);
        }
        let rhos: Vec<DensityMemory> = results.iter().map(|r| r.memory.clone()).collect();
        let blur = if let Ok(hugin) = self.hugin.lock() {
            hugin.blurring_score(&rhos)
        } else {
            0.0
        };
        let mut total_lyapunov = 0.0f32;
        if let Ok(vaf) = self.vafthrudnir.lock() {
            for res in results.iter() {
                total_lyapunov += vaf.lyapunov_exponent(&res.id.to_string(), 1);
            }
        }
        let mean_lyapunov = total_lyapunov / results.len() as f32;
        if let Ok(mut hugin) = self.hugin.lock() {
            hugin.competitive_step(0.05);
        }
        let metastability = (1.0 - blur) * (1.0 + mean_lyapunov);
        if metastability < 0.5 {
            tracing::warn!("Manifold chaos detected! Triggering emergency consolidation.");
            let _ = self.consolidate().await?;
        }
        Ok(metastability)
    }

    async fn consolidate(&self) -> Result<ConsolidationReport, MimirError> {
        let start = std::time::Instant::now();
        tracing::info!("Starting memory consolidation cycle (Muninn)");

        let query = RecallQuery::new("").with_limit(1000);
        let candidates = self.well.minni(query).await?;

        let mut report = ConsolidationReport {
            memories_processed: candidates.len(),
            memories_promoted: 0,
            memories_demoted: 0,
            blocks_processed: 0,
            duration_ms: 0,
            errors: Vec::new(),
        };

        // Phase 3.2: Manifold Restructuring
        let mut rhos: Vec<DensityMemory> =
            candidates.iter().map(|r| r.memory.clone()).collect();
        if let Err(e) = mimirs_sleeptime::Drauma::restructure_manifold(&mut rhos) {
            report.errors.push(format!("Manifold restructuring failed: {}", e));
        }

        // Phase 3.3: Write restructured rhos back
        for (i, rho) in rhos.iter().enumerate() {
            if i < candidates.len() {
                if let Ok(mut mem) = self.well.get_memory(candidates[i].id) {
                    mem.rho = Some(rho.clone());
                    if let Err(e) = self.well.rista(&mem) {
                        report.errors.push(format!("Restructured memory write failed: {}", e));
                    }
                }
            }
        }

        // Consolidation mixing
        for i in 0..candidates.len() {
            let res = &candidates[i];
            let should_consolidate = if let Ok(hugin) = self.hugin.lock() {
                hugin.should_consolidate(res.memory.purity())
            } else {
                false
            };

            if should_consolidate && i + 1 < candidates.len() {
                let other = &candidates[i + 1];
                let importance =
                    mimirs_forget::Galdr::estimate(&res.memory, mimirs_core::ScrambleScore(0.5));
                let consolidation_result = if let Ok(mun) = self.muninn.lock() {
                    mun.consolidate(&res.memory, &other.memory, &importance)
                } else {
                    Err(MimirError::Uninitialized("Muninn lock failed".to_string()))
                };

                match consolidation_result {
                    Ok(mixed) => {
                        let res_mem = self.well.get_memory(res.id).unwrap_or_else(|_| Memory {
                            id: res.id,
                            content: String::new(),
                            ..Default::default()
                        });
                        let other_mem = self.well.get_memory(other.id).unwrap_or_else(|_| Memory {
                            id: other.id,
                            content: String::new(),
                            ..Default::default()
                        });
                        let mixed_memory = Memory {
                            id: MemoryId::new(),
                            content: format!("Abstraction of {} and {}", res_mem.content, other_mem.content),
                            metadata: Default::default(),
                            scope: mimirs_core::MemoryScope::Agent,
                            verifiability: mimirs_core::VerifiabilityStage::Verified,
                            memory_class: mimirs_core::MemoryClass::Semantic,
                            rho: Some(mixed),
                            qrc_state: None,
                            scramble_score: None,
                            source_session: Some(self.session_id.clone()),
                        };

                        if let Err(e) = self.well.rista(&mixed_memory) {
                            report.errors.push(e.to_string());
                        } else {
                            report.memories_promoted += 1;
                        }
                    }
                    Err(e) => report.errors.push(e.to_string()),
                }
            }
        }

        // Phase 2.5: Generative replay
        if let Ok(mun) = self.muninn.lock() {
            let replay_samples = mun.sample_replay(10);
            if !replay_samples.is_empty() {
                tracing::debug!(count = replay_samples.len(), "Replaying from generative distillation buffer");
            }
        }

        report.duration_ms = start.elapsed().as_millis() as u64;

        if let Err(e) = self.bus.broadcast(MemorySignal::ConsolidationCompleted {
            agent_id: self.yggdrasil.identity.id,
            memories_processed: report.memories_processed,
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for ConsolidationCompleted");
        }

        Ok(report)
    }

    async fn reflect(&self) -> Result<(), MimirError> {
        if let Some(ref nott) = self.nott {
            nott.drauma().await
        } else {
            Err(MimirError::Uninitialized("Reflection engine not set".to_string()))
        }
    }

    async fn snapshot(&self) -> Result<MemorySnapshot, MimirError> {
        let query = RecallQuery::new("").with_limit(10000);
        let memories = self.well.minni(query).await?;
        let blocks = self.well.minni_block()?;
        Ok(MemorySnapshot {
            memories: memories.into_iter().filter_map(|m| self.well.get_memory(m.id).ok()).collect(),
            blocks,
            goals: self.nott.as_ref().map(|n| n.goals.active_goals.clone()).unwrap_or_default(),
            identity: Some(self.yggdrasil.identity.clone()),
            timestamp: chrono::Utc::now().to_rfc3339(),
            version: env!("CARGO_PKG_VERSION").to_string(),
        })
    }

    async fn attach_block(&self, block: MemoryBlock) -> Result<BlockId, MimirError> {
        let id = block.id;
        self.well.rista_block(&block)?;
        if let Ok(mut saga) = self.saga.lock()
            && let Err(e) = saga.skrifa(SagaEntry::BlockAttached {
                agent_id: self.yggdrasil.identity.id,
                block: block.clone(),
            })
        {
            tracing::warn!(error = %e, "Saga WAL write failed for BlockAttached");
        }
        if let Err(e) = self.bus.broadcast(MemorySignal::BlockAttached {
            agent_id: self.yggdrasil.identity.id,
            block_id: id,
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for BlockAttached");
        }
        Ok(id)
    }

    async fn detach_block(&self, id: BlockId) -> Result<MemoryBlock, MimirError> {
        let blocks = self.well.minni_block()?;
        let block = blocks
            .into_iter()
            .find(|b| b.id == id)
            .ok_or_else(|| MimirError::Validation(format!("Block {} not found", id)))?;
        if let Ok(mut saga) = self.saga.lock()
            && let Err(e) = saga.skrifa(SagaEntry::BlockDetached {
                agent_id: self.yggdrasil.identity.id,
                block_id: id,
            })
        {
            tracing::warn!(error = %e, "Saga WAL write failed for BlockDetached");
        }
        if let Err(e) = self.bus.broadcast(MemorySignal::BlockDetached {
            agent_id: self.yggdrasil.identity.id,
            block_id: id,
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for BlockDetached");
        }
        Ok(block)
    }

    async fn update_block(&self, id: BlockId, value: String) -> Result<(), MimirError> {
        let mut block = self.detach_block(id).await?;
        block.value = value;
        self.attach_block(block).await?;
        Ok(())
    }

    async fn list_blocks(&self) -> Result<Vec<MemoryBlock>, MimirError> {
        self.well.minni_block()
    }

    async fn get_memory(&self, id: MemoryId) -> Result<Memory, MimirError> {
        self.well.get_memory(id)
    }

    async fn update_memory(&self, memory: Memory) -> Result<(), MimirError> {
        self.well.rista(&memory)?;
        if let Err(e) = self.bus.broadcast(MemorySignal::MemoryStored {
            agent_id: self.yggdrasil.identity.id,
            memory_id: memory.id,
            memory_class: memory.memory_class,
        }) {
            tracing::warn!(error = %e, "EventBus broadcast failed for MemoryStored update");
        }
        Ok(())
    }

    async fn propagate(&self, u: &nalgebra::DMatrix<f32>) -> Result<(), MimirError> {
        let query = RecallQuery::new("").with_limit(1000);
        let results = self.well.minni(query).await?;
        for res in results {
            if let Ok(mut mem) = self.well.get_memory(res.id)
                && let Some(ref mut rho) = mem.rho
            {
                if let Err(e) = rho.propagate(u) {
                    tracing::error!(memory_id = %res.id, error = %e, "Propagation failed");
                    continue;
                }
                self.well.rista(&mem)?;
            }
        }
        Ok(())
    }
}
