use ndarray::{ArrayBase, Data, Dimension, Ix2, ViewRepr};
use std::any::TypeId;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
pub struct ChunkProcessor<'a, A, S, D>
where
    S: Data<Elem = A>,
    D: Dimension,
{
    array: &'a ArrayBase<S, D>,
        #[allow(dead_code)]
    chunk_shape: D,
        #[allow(dead_code)]
    position: D,
}
impl<'a, A, S, D> ChunkProcessor<'a, A, S, D>
where
    S: Data<Elem = A>,
    D: Dimension,
{
        pub fn new(array: &'a ArrayBase<S, D>, chunk_shape: D) -> Self {
        let position = D::zeros(array.ndim());
        Self {
            array,
            chunk_shape,
            position,
        }
    }
        pub fn process_chunks<F>(&mut self, mut f: F)
    where
        F: FnMut(&ArrayBase<ViewRepr<&A>, D>, D),
    {
                        let position = D::zeros(self.array.ndim());
                        f(&self.array.view(), position);
    }
        pub fn num_chunks(&self) -> usize {
                        1
    }
}
pub struct ChunkProcessor2D<'a, A, S>
where
    S: Data<Elem = A>,
{
    array: &'a ArrayBase<S, Ix2>,
    chunk_shape: (usize, usize),
        #[allow(dead_code)]
    current_row: usize,
    #[allow(dead_code)]
    current_col: usize,
}
impl<'a, A, S> ChunkProcessor2D<'a, A, S>
where
    S: Data<Elem = A>,
{
        pub fn new(array: &'a ArrayBase<S, Ix2>, chunk_shape: (usize, usize)) -> Self {
        Self {
            array,
            chunk_shape,
            current_row: 0,
            current_col: 0,
        }
    }
        pub fn process_chunks<F>(&mut self, mut f: F)
    where
        F: FnMut(&ArrayBase<ViewRepr<&A>, Ix2>, (usize, usize)),
    {
        let (rows, cols) = self.array.dim();
        let (chunk_rows, chunk_cols) = self.chunk_shape;
        for row_start in (0..rows).step_by(chunk_rows) {
            for col_start in (0..cols).step_by(chunk_cols) {
                let row_end = (row_start + chunk_rows).min(rows);
                let col_end = (col_start + chunk_cols).min(cols);
                                let chunk = self
                    .array
                    .slice(ndarray::s![row_start..row_end, col_start..col_end]);
                                f(&chunk, (row_start, col_start));
            }
        }
    }
}
pub struct BufferPool<T: Clone + Default> {
            vectors: Vec<Vec<T>>,
    arrays: Vec<ndarray::Array1<T>>,
}
impl<T: Clone + Default> BufferPool<T> {
        pub fn new() -> Self {
        Self {
            vectors: Vec::new(),
            arrays: Vec::new(),
        }
    }
        pub fn acquire_vec(&mut self, capacity: usize) -> Vec<T> {
                for i in 0..self.vectors.len() {
            if self.vectors[i].capacity() >= capacity {
                                let mut vec = self.vectors.swap_remove(i);
                vec.clear();
                vec.resize(capacity, T::default());
                return vec;
            }
        }
                vec![T::default(); capacity]
    }
        pub fn release_vec(&mut self, vec: Vec<T>) {
                self.vectors.push(vec);
    }
        pub fn acquire_array(&mut self, size: usize) -> ndarray::Array1<T> {
                for i in 0..self.arrays.len() {
            if self.arrays[i].len() >= size {
                                let mut array = self.arrays.swap_remove(i);
                                if array.len() != size {
                    array = ndarray::Array1::from_elem(size, T::default());
                }
                return array;
            }
        }
                ndarray::Array1::from_elem(size, T::default())
    }
        pub fn release_array(&mut self, array: ndarray::Array1<T>) {
                self.arrays.push(array);
    }
        pub fn clear(&mut self) {
        self.vectors.clear();
        self.arrays.clear();
    }
}
impl<T: Clone + Default> Default for BufferPool<T> {
    fn default() -> Self {
        Self::new()
    }
}
pub struct GlobalBufferPool {
        pools: Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
}
impl GlobalBufferPool {
        pub fn new() -> Self {
        Self {
            pools: Mutex::new(HashMap::new()),
        }
    }
        pub fn get_pool<T: Clone + Default + 'static + Send + Sync>(
        &self,
    ) -> Arc<Mutex<BufferPool<T>>> {
        let type_id = TypeId::of::<T>();
        let mut pools = self.pools.lock().unwrap();
        use std::collections::hash_map::Entry;
        match pools.entry(type_id) {
            Entry::Vacant(entry) => {
                                let pool = Arc::new(Mutex::new(BufferPool::<T>::new()));
                entry.insert(Box::new(pool.clone()));
                pool
            }
            Entry::Occupied(entry) => {
                                match entry.get().downcast_ref::<Arc<Mutex<BufferPool<T>>>>() {
                    Some(pool) => pool.clone(),
                    None => panic!("Type mismatch in global buffer pool"),
                }
            }
        }
    }
        pub fn clear_all(&self) {
        let mut pools = self.pools.lock().unwrap();
        pools.clear();
    }
}
impl Default for GlobalBufferPool {
    fn default() -> Self {
        Self::new()
    }
}
pub fn global_buffer_pool() -> &'static GlobalBufferPool {
    use once_cell::sync::Lazy;
    static GLOBAL_POOL: Lazy<GlobalBufferPool> = Lazy::new(GlobalBufferPool::new);
    &GLOBAL_POOL
}
pub struct ZeroCopyView<'a, T, D>
where
    D: Dimension,
{
    _phantom: PhantomData<T>,
    inner: ndarray::ArrayView<'a, T, D>,
}
impl<'a, T, D> ZeroCopyView<'a, T, D>
where
    D: Dimension,
{
        pub fn new(array: &'a ndarray::Array<T, D>) -> Self {
        Self {
            _phantom: PhantomData,
            inner: array.view(),
        }
    }
        pub fn view(&self) -> ndarray::ArrayView<'a, T, D> {
        self.inner.clone()
    }
        pub fn transform<F, U>(&self, f: F) -> ndarray::Array<U, D>
    where
        F: Fn(&T) -> U,
        U: Clone,
    {
        self.inner.map(f)
    }
}
pub struct MemoryTracker {
    allocations: Mutex<HashMap<String, usize>>,
}
impl MemoryTracker {
        pub fn new() -> Self {
        Self {
            allocations: Mutex::new(HashMap::new()),
        }
    }
}
impl Default for MemoryTracker {
    fn default() -> Self {
        Self::new()
    }
}
impl MemoryTracker {
        pub fn track_allocation(&self, name: &str, size: usize) {
        let mut allocations = self.allocations.lock().unwrap();
        *allocations.entry(name.to_string()).or_insert(0) += size;
    }
        pub fn track_deallocation(&self, name: &str, size: usize) {
        let mut allocations = self.allocations.lock().unwrap();
        if let Some(current) = allocations.get_mut(name) {
            *current = current.saturating_sub(size);
        }
    }
        pub fn get_usage(&self, name: &str) -> usize {
        let allocations = self.allocations.lock().unwrap();
        allocations.get(name).copied().unwrap_or_default()
    }
        pub fn get_total_usage(&self) -> usize {
        let allocations = self.allocations.lock().unwrap();
        allocations.values().sum()
    }
        pub fn reset(&self) {
        let mut allocations = self.allocations.lock().unwrap();
        allocations.clear();
    }
}
pub fn global_memory_tracker() -> &'static MemoryTracker {
    use once_cell::sync::Lazy;
    static GLOBAL_TRACKER: Lazy<MemoryTracker> = Lazy::new(MemoryTracker::new);
    &GLOBAL_TRACKER
}
pub mod metrics;
pub use metrics::{
    format_memory_report, generate_memory_report, track_allocation, track_deallocation,
    track_resize,
};