use mimirs_core::{
    AgentId, BlockId, ConsolidationReport, DensityMemory, Memory, MemoryAgent, MemoryBlock,
    MemoryId, MemoryInput, MemorySnapshot, MimirError, 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).
/// Nordic-named internal components:
/// - well: Urdarbrunnr (The Unified Store)
/// - hugin: The temporal decay raven (Scheduler)
/// - muninn: The memory consolidation raven (Anti-forgetting)
/// - vafthrudnir: The OTOC scrambling oracle (Structural Criticality)
/// - forseti: The verifiability oracle (Judgment)
/// - ginnunga: The contradiction detector (Chaos)
/// - saga: The write-ahead log (History)
/// - thing: The consensus assembly (Consensus)
/// - nott: The reflection engine (Night/Reflection)
/// - yggdrasil: The global self-model (Identity)
/// - bus: EventBus (Real-time broadcast)
#[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: IdentityKnot,
    encoder: Option<mimirs_encoding::SharedEncoder>,
    sleipnir: Option<Arc<mimirs_encoding::SleipnirEngine>>,
    quorum: Arc<mimirs_ha::ElderQuorum>,
    /// Embedding dimension for fallback hash-based encoding.
    manifold_dim: usize,
}

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());

        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: IdentityKnot::new(
                mimirs_core::DensityMemory::from_pure(&{
                    let mut v = vec![0.0; 128];
                    v[0] = 1.0;
                    v
                })
                .unwrap(),
            ),
            encoder: None,
            sleipnir: None,
            quorum,
            manifold_dim: config.manifold_dim,
        }
    }

    /// Attaches a semantic encoder for real vector embeddings.
    pub fn with_encoder(mut self, encoder: mimirs_encoding::SharedEncoder) -> Self {
        self.encoder = Some(encoder);
        self
    }

    /// Attempts to load the default semantic encoder (transformer-based).
    pub fn load_semantic_encoder(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        let encoder = mimirs_encoding::SemanticEncoder::load_default()?;
        self.encoder = Some(Arc::new(encoder));
        Ok(())
    }

    /// Attaches a Sleipnir cognitive engine for continuous-time dynamics (Phase 10).
    pub fn with_sleipnir(mut self, sleipnir: Arc<mimirs_encoding::SleipnirEngine>) -> Self {
        self.sleipnir = Some(sleipnir);
        self
    }

    /// Attempts to load the default Sleipnir engine (Liquid LFM 2.5) from models/sleipnir.gguf.
    pub fn load_sleipnir_default(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        let path = std::path::Path::new("models/sleipnir.gguf");
        let sleipnir = mimirs_encoding::SleipnirEngine::load(path, mimirs_wyrd::Device::Cpu)?;
        self.sleipnir = Some(Arc::new(sleipnir));
        Ok(())
    }

    /// 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<f64, 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.sync_anchors(&index, memories)
    }

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

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

// 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)
        let rho = if entry.content.is_empty() {
            None
        } else if let Some(ref sleipnir) = self.sleipnir {
            // Phase 10: Sleipnir Continuous-Time Dynamics
            match sleipnir.encode_with_dynamics(&entry.content, 0.0) {
                Ok(rho) => Some(rho),
                Err(e) => {
                    tracing::error!(error = %e, "Sleipnir encoding failed");
                    None
                }
            }
        } else if let Some(ref encoder) = self.encoder {
            // Real transformer-based encoding (Layer 1)
            match encoder.encode(&entry.content) {
                Ok(vec) => mimirs_core::DensityMemory::from_pure(&vec).ok(),
                Err(e) => {
                    tracing::error!(error = %e, "Semantic encoding failed, falling back to dummy");
                    None
                }
            }
        } else {
            use std::hash::{Hash, Hasher};
            let mut hasher = std::collections::hash_map::DefaultHasher::new();
            entry.content.hash(&mut hasher);
            let seed = hasher.finish();

            // DERIVATION: Pseudo-random projection x -> ℝᵈ where d=manifold_dim.
            // Uses a Linear Congruential Generator (LCG) projection to ensure
            // zero-centered, deterministic distribution for high-fidelity fallbacks.
            let mut embedding = vec![0.0f64; self.manifold_dim];
            for (i, val) in embedding.iter_mut().enumerate() {
                let v = ((seed.wrapping_add(i as u64)).wrapping_mul(0x632BE59BD9B4E019)) as f64
                    / u64::MAX as f64;
                *val = v * 2.0 - 1.0; // Zero-centered
            }
            mimirs_core::DensityMemory::from_pure(&embedding).ok()
        };

        // 1. Register Activity and Tune Reservoir (Phase 10 Dynamic ε)
        if let Ok(mut hugin) = self.hugin.lock() {
            hugin.register_activity(id, 0.5); // Initial boost

            // Dynamic ε Tuning based on Sleipnir complexity
            if let Some(ref sleipnir) = self.sleipnir {
                let epsilon = sleipnir.predict_complexity(&entry.content);
                hugin.tune_epsilon(epsilon);
                tracing::debug!(epsilon = %epsilon, "Tuned reservoir reset rate");
            }
        }

        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,
        };

        tracing::debug!("Carving memory into Urdarbrunnr");
        self.well.rista(&memory)?;

        // 2. Record Initial Gradient for OTOC (Phase 3.1)
        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.iter().map(|&x| x as f32).collect::<Vec<_>>(),
                );
            }

            // 3. Push to Generative Replay Buffer (L5)
            if let Ok(mut mun) = self.muninn.lock() {
                mun.push_to_replay(rho);
            }
        }

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::MemoryStored {
            agent_id: self.yggdrasil.identity.id,
            memory_id: id,
            memory_class: memory.memory_class,
        });

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

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

        // Vectorize query if encoder is available
        if let Some(ref sleipnir) = self.sleipnir {
            // Phase 10: Sleipnir Query (LNN-based)
            if let Ok(q_rho) = sleipnir.encode_with_dynamics(&query.query, 0.0) {
                query = query.with_query_rho(q_rho);
            }
        } else if let Some(ref encoder) = self.encoder
            && let Ok(vec) = encoder.encode(&query.query)
            && let Ok(q_rho) = mimirs_core::DensityMemory::from_pure(&vec)
        {
            query = query.with_query_rho(q_rho);
        }

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

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::MemoryRecalled {
            agent_id: self.yggdrasil.identity.id,
            query: query.query,
            results_count: results.len(),
        });

        // 3. Register Activity for recalled memories (Phase 2.2)
        if let Ok(mut hugin) = self.hugin.lock() {
            for res in results.iter() {
                hugin.register_activity(res.id, 0.2); // Recall boost
            }
        }

        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)");
        self.well.eyda(id)
    }

    /// Monitor the semantic manifold for Edge Metastability (Phase 4.1).
    /// Returns the "Metastability" score. Optimal range is 0.7-0.9 (Edge of Chaos).
    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); // Fully stable if empty
        }

        let rhos: Vec<mimirs_core::DensityMemory> =
            results.iter().map(|r| r.memory.clone()).collect();

        // 1. Compute Spectral Blurring (Chaos measure)
        let blur = if let Ok(hugin) = self.hugin.lock() {
            hugin.blurring_score(&rhos)
        } else {
            0.0
        };

        // 2. Compute Mean Lyapunov Exponent (Scrambling measure)
        let mut total_lyapunov = 0.0f64;
        if let Ok(vaf) = self.vafthrudnir.lock() {
            for res in results.iter() {
                let id_str = res.id.to_string();
                total_lyapunov += vaf.lyapunov_exponent(&id_str, 1);
            }
        }
        let mean_lyapunov = (total_lyapunov / results.len() as f64) as f32;

        // 3. Advance Competitive Inhibition state
        if let Ok(mut hugin) = self.hugin.lock() {
            hugin.competitive_step(0.05); // Ambient decay
        }

        // DERIVATION: Metastability λ = (1 - S_blur) * (1 + λ_max).
        // Measures the "Edge of Chaos" balance between spectral blurring (entropy)
        // and Lyapunov scrambling (chaos). Optimal range: 0.7 - 0.9.
        let metastability = (1.0 - blur) * (1.0 + mean_lyapunov);

        tracing::info!(metastability = %metastability, blur = %blur, lyapunov = %mean_lyapunov, "Criticality Monitor");

        // Trigger emergency consolidation if we drift too far into chaos (metastability < 0.5)
        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)");

        // 1. Scan for memories below coherence threshold using Hugin
        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: Perform Manifold Restructuring on candidates
        let mut rhos: Vec<mimirs_core::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));
        }

        // 2. Logic for consolidation (mixing density matrices)
        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 {
                // Find another similar memory to mix with
                if let Some(other) = candidates.get(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) => {
                            // 2. Synthesize a more meaningful abstraction (L3)
                            let mut mixed_memory = if let Ok(mun) = self.muninn.lock() {
                                mun.abstrahera(&[
                                    self.well.get_memory(res.id).unwrap_or_else(|_| Memory {
                                        id: res.id,
                                        content: "Unknown".to_string(),
                                        ..Default::default()
                                    }),
                                    self.well.get_memory(other.id).unwrap_or_else(|_| Memory {
                                        id: other.id,
                                        content: "Unknown".to_string(),
                                        ..Default::default()
                                    }),
                                ])?
                            } else {
                                // Fallback if lock fails
                                Memory {
                                    id: MemoryId::new(),
                                    content: "Consolidated abstraction (fallback)".to_string(),
                                    ..Default::default()
                                }
                            };

                            mixed_memory.rho = Some(mixed);
                            mixed_memory.memory_class = mimirs_core::MemoryClass::Semantic;
                            mixed_memory.verifiability = mimirs_core::VerifiabilityStage::Verified;

                            if let Err(e) = self.well.rista(&mixed_memory) {
                                report.errors.push(e.to_string());
                            } else {
                                tracing::debug!(
                                    "Consolidated memories into abstraction with purity {}",
                                    mixed_memory.rho.as_ref().unwrap().purity()
                                );
                                report.memories_promoted += 1;

                                // Emit signal for the new consolidated memory
                                let _ = self.bus.broadcast(MemorySignal::MemoryStored {
                                    agent_id: self.yggdrasil.identity.id,
                                    memory_id: mixed_memory.id,
                                    memory_class: mixed_memory.memory_class,
                                });
                            }
                        }
                        Err(e) => report.errors.push(e.to_string()),
                    }
                }
            }
        }

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

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::ConsolidationCompleted {
            agent_id: self.yggdrasil.identity.id,
            memories_processed: report.memories_processed,
        });

        tracing::info!(
            processed = report.memories_processed,
            "Consolidation complete"
        );
        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> {
        tracing::info!("Creating memory snapshot");
        let query = RecallQuery::new("").with_limit(10000);
        let memories = self.well.minni(query).await?;
        let blocks = self.well.minni_block()?;

        let mut memories_to_save = Vec::new();
        for m in memories {
            if let Ok(full_mem) = self.well.get_memory(m.id) {
                memories_to_save.push(full_mem);
            }
        }

        Ok(MemorySnapshot {
            memories: memories_to_save,
            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: "0.1.0".to_string(),
        })
    }

    // ============== Memory Block Operations ==============

    async fn attach_block(&self, block: MemoryBlock) -> Result<BlockId, MimirError> {
        tracing::info!(block_id = %block.id, "Attaching memory block to store");
        let id = block.id;
        self.well.rista_block(&block)?;

        // Record in Saga WAL
        if let Ok(mut saga) = self.saga.lock() {
            let _ = saga.skrifa(SagaEntry::BlockAttached {
                agent_id: self.yggdrasil.identity.id,
                block: block.clone(),
            });
        }

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::BlockAttached {
            agent_id: self.yggdrasil.identity.id,
            block_id: id,
        });

        Ok(id)
    }

    async fn detach_block(&self, id: BlockId) -> Result<MemoryBlock, MimirError> {
        tracing::info!(block_id = %id, "Detaching memory block from store");
        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)))?;

        // Record in Saga WAL
        if let Ok(mut saga) = self.saga.lock() {
            let _ = saga.skrifa(SagaEntry::BlockDetached {
                agent_id: self.yggdrasil.identity.id,
                block_id: id,
            });
        }

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::BlockDetached {
            agent_id: self.yggdrasil.identity.id,
            block_id: id,
        });

        Ok(block)
    }

    async fn update_block(&self, id: BlockId, value: String) -> Result<(), MimirError> {
        tracing::info!(block_id = %id, "Updating memory block");
        let mut block = self.detach_block(id).await?;
        block.value = value;
        let _ = 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> {
        tracing::info!(memory_id = %memory.id, "Updating memory in well");
        self.well.rista(&memory)?;

        // Emit signal
        let _ = self.bus.broadcast(MemorySignal::MemoryStored {
            agent_id: self.yggdrasil.identity.id,
            memory_id: memory.id,
            memory_class: memory.memory_class,
        });

        Ok(())
    }

    async fn propagate(&self, u: &nalgebra::DMatrix<f64>) -> Result<(), MimirError> {
        tracing::info!("Propagating global cognitive state");

        // 1. Fetch all episodic and semantic memories
        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 for memory");
                    continue;
                }
                // Save the evolved state
                self.well.rista(&mem)?;
            }
        }

        Ok(())
    }
}
