use crate::prelude::*;

use core::future::ready;
use core::iter::Map;
use std::collections::hash_set::{HashSet, Iter};
use std::iter::Cloned;

use futures::future::OkInto;
use futures::stream;
use taganak_core::default_graph_view;
use taganak_core::graphs::GraphView;
use taganak_core::triples::TripleRef;

#[derive(Debug, Default, Clone)]
pub struct SimpleGraph(HashSet<Arc<Triple>>);

impl Graph for SimpleGraph {
    type View<'g> = &'g Self;

    fn view(&self) -> impl core::future::Future<Output = Self::View<'_>> + Send {
        core::future::ready(self)
    }

    fn add(
        &mut self,
        triple: Arc<Triple>,
    ) -> impl core::future::Future<Output = Result<(), GraphError>> + Send {
        self.0.insert(triple);
        core::future::ready(Ok(()))
    }

    fn remove(
        &mut self,
        triple: TripleRef<'_>,
    ) -> impl core::future::Future<Output = Result<(), GraphError>> + Send {
        self.0.remove(&triple.to_triple());
        core::future::ready(Ok(()))
    }

    fn clear(&mut self) -> impl core::future::Future<Output = Result<(), GraphError>> + Send {
        self.0.clear();
        core::future::ready(Ok(()))
    }
}

fn ok_enum(t: Arc<Triple>) -> Result<Arc<Triple>, GraphError> {
    Ok(t)
}

impl<'g> GraphView for &'g SimpleGraph {
    type Stream = stream::Iter<
        Map<Cloned<Iter<'g, Arc<Triple>>>, fn(Arc<Triple>) -> Result<Arc<Triple>, GraphError>>,
    >;

    fn stream(self) -> impl core::future::Future<Output = Result<Self::Stream, GraphError>> + Send {
        core::future::ready(Ok(stream::iter(self.0.iter().cloned().map(ok_enum as _))))
    }

    default_graph_view!();
}

impl SimpleGraph {
    pub fn add_sync(&mut self, triple: Arc<Triple>) {
        self.0.insert(triple);
    }
}
