use std::cell::RefCell;
use std::path::{Path, PathBuf};
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use crate::system::model::DLASystem;
use crate::system::{Storage};
use crate::system::spaces::square_grid::Grid2D;
use crate::system::spaces::VectorStorage;
use crate::system::spawner::UniformSpawner;
use crate::system::sticker::{ProbabilisticSticking, SimpleSticking, Sticker};
use crate::system::walker::LocalRandomWalker;

pub struct LoggerSticker {
    inner: ProbabilisticSticking,
    pub stick_positions: RefCell<Vec<Grid2D>>,
}

impl LoggerSticker {
    pub fn new(stick_probability: f32) -> LoggerSticker {
        LoggerSticker {
            inner: ProbabilisticSticking { stick_probability },
            stick_positions: RefCell::new(Vec::new()),
        }
    }
}

impl<S: Storage<Grid2D>> Sticker<Grid2D, S> for &LoggerSticker {
    fn should_stick<R: Rng>(&self, rng: &mut R, space: &S, position: &Grid2D) -> bool {
        let should_stick = self.inner.should_stick(rng, space, position);

        if should_stick {
            self.stick_positions.borrow_mut()
                .push(position.clone());
        }

        // Writes are ignored so we deposit to delete the particle but it is not written
        should_stick
    }
}

pub struct ReadOnlyVectorStorage {
    inner: VectorStorage,
}

impl ReadOnlyVectorStorage {
    pub fn new(path: &Path, grid_size: u32) -> ReadOnlyVectorStorage {
        let mut inner = VectorStorage::new(grid_size, 2);
        let positions: Vec<Grid2D> = csv::Reader::from_path(path)
            .expect("Failed to read initial data")
            .deserialize::<Grid2D>()
            .map(|row| row.expect("Failed to read row"))
            .collect();

        for pos in positions {
            inner.deposit(&pos);
        }

        ReadOnlyVectorStorage { inner }
    }
}

impl Storage<Grid2D> for ReadOnlyVectorStorage {
    fn is_occupied(&self, position: &Grid2D) -> bool {
        self.inner.is_occupied(position)
    }

    fn deposit(&mut self, position: &Grid2D) {
        eprintln!("Write ignored for space at {position:?}");
    }
}
