// Copyright 2025 Neuraville Inc.
// SPDX-License-Identifier: Apache-2.0

/*!
Direct neuron parameter update service for cortical areas.

This module enables updating neuron properties directly in the NPU
without requiring expensive full brain rebuilds or synapse regeneration,
providing massive performance improvements for parameter-only changes.

Based on Python implementation at: feagi-py/feagi/api/core/services/genome/parameter_updater.py

Copyright 2025 Neuraville Inc.
Licensed under the Apache License, Version 2.0
*/

// use feagi_npu_burst_engine::RustNPU; // Now using DynamicNPU
use serde_json::Value;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use tracing::{error, info, warn};

use crate::ServiceResult;

/// Handles direct neuron parameter updates without full brain rebuild or synapse regeneration
///
/// ARCHITECTURE: This service updates neuron properties directly in the NPU.
/// It does NOT rebuild synapses or change neuron topology.
///
/// Performance: ~2-5ms vs ~100-200ms for synapse rebuild (20-40x faster)
pub struct CorticalParameterUpdater {
    npu: Arc<Mutex<feagi_npu_burst_engine::DynamicNPU>>,
}

impl CorticalParameterUpdater {
    pub fn new(npu: Arc<Mutex<feagi_npu_burst_engine::DynamicNPU>>) -> Self {
        Self { npu }
    }

    /// Update neuron parameters for a cortical area via NPU batch updates
    ///
    /// ARCHITECTURE: NPU owns all neurons. This service tells NPU which cortical area
    /// and what values to update. NPU does everything internally in batch.
    ///
    /// # Arguments
    /// * `cortical_idx` - Cortical area index (NOT cortical_id string)
    /// * `parameter_changes` - Map of parameter_name -> new_value
    ///
    /// # Returns
    /// Number of successfully updated parameters
    pub fn update_neuron_parameters(
        &self,
        cortical_idx: u32,
        cortical_id: &str,
        parameter_changes: &HashMap<String, Value>,
    ) -> ServiceResult<usize> {
        let mut success_count = 0;
        let mut npu = self.npu.lock().unwrap();

        for (param_name, value) in parameter_changes {
            let updated = match param_name.as_str() {
                // Firing threshold
                "neuron_fire_threshold" | "firing_threshold" => {
                    if let Some(threshold) = value.as_f64() {
                        let count =
                            npu.update_cortical_area_threshold(cortical_idx, threshold as f32);
                        info!(
                            "✓ Synced firing_threshold={} to {} neurons in area {}",
                            threshold, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Firing threshold limit (different from firing threshold)
                "neuron_firing_threshold_limit" | "firing_threshold_limit" => {
                    if let Some(limit) = value.as_f64() {
                        let count =
                            npu.update_cortical_area_threshold_limit(cortical_idx, limit as f32);
                        info!(
                            "✓ Synced firing_threshold_limit={} to {} neurons in area {}",
                            limit, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Refractory period
                "neuron_refractory_period" | "refractory_period" | "refrac" => {
                    if let Some(period) = value.as_u64() {
                        let count =
                            npu.update_cortical_area_refractory_period(cortical_idx, period as u16);
                        info!(
                            "✓ Synced refractory_period={} to {} neurons in area {}",
                            period, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Leak coefficient
                "leak" | "leak_coefficient" | "neuron_leak_coefficient" => {
                    if let Some(leak) = value.as_f64() {
                        if !(0.0..=1.0).contains(&leak) {
                            error!("Leak coefficient must be in range 0.0-1.0, got {}", leak);
                            0
                        } else {
                            let count = npu.update_cortical_area_leak(cortical_idx, leak as f32);
                            info!(
                                "✓ Synced leak_coefficient={} to {} neurons in area {}",
                                leak, count, cortical_id
                            );
                            count
                        }
                    } else {
                        0
                    }
                }

                // Consecutive fire limit
                "consecutive_fire_cnt_max"
                | "neuron_consecutive_fire_count"
                | "consecutive_fire_count" => {
                    if let Some(limit) = value.as_u64() {
                        let count = npu.update_cortical_area_consecutive_fire_limit(
                            cortical_idx,
                            limit as u16,
                        );
                        info!(
                            "✓ Synced consecutive_fire_limit={} to {} neurons in area {}",
                            limit, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Snooze period
                "snooze_length" | "neuron_snooze_period" | "snooze_period" => {
                    if let Some(snooze) = value.as_u64() {
                        let count =
                            npu.update_cortical_area_snooze_period(cortical_idx, snooze as u16);
                        info!(
                            "✓ Synced snooze_period={} to {} neurons in area {}",
                            snooze, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Excitability
                "neuron_excitability" => {
                    if let Some(excitability) = value.as_f64() {
                        if !(0.0..=1.0).contains(&excitability) {
                            error!(
                                "Excitability must be in range 0.0-1.0, got {}",
                                excitability
                            );
                            0
                        } else {
                            let count = npu.update_cortical_area_excitability(
                                cortical_idx,
                                excitability as f32,
                            );
                            info!(
                                "✓ Synced excitability={} to {} neurons in area {}",
                                excitability, count, cortical_id
                            );
                            count
                        }
                    } else {
                        0
                    }
                }

                // MP charge accumulation
                "neuron_mp_charge_accumulation" | "mp_charge_accumulation" => {
                    if let Some(accumulation) = value.as_bool() {
                        let count = npu.update_cortical_area_mp_charge_accumulation(
                            cortical_idx,
                            accumulation,
                        );
                        info!(
                            "✓ Synced mp_charge_accumulation={} to {} neurons in area {}",
                            accumulation, count, cortical_id
                        );
                        count
                    } else {
                        0
                    }
                }

                // Other parameters - not yet implemented for live update
                _ => {
                    warn!(
                        "Live update for parameter '{}' not yet implemented - will require restart",
                        param_name
                    );
                    0
                }
            };

            if updated > 0 {
                success_count += 1;
            }
        }

        info!(
            "[FAST-UPDATE] Completed {}/{} parameter updates for cortical area {}",
            success_count,
            parameter_changes.len(),
            cortical_id
        );

        Ok(success_count)
    }
}
