#[cfg(feature = "source_n_triples")]
pub mod n_triples;

#[cfg(feature = "source_turtle")]
pub mod turtle;

use std::sync::Mutex;

use crate::prelude::*;

use tracing::debug;

use tokio::io::AsyncWriteExt;

pub trait GraphSerializer {
    // FIXME this API needs overhauling once we write more complicated serializers that require Graph access
    fn write_all<G, W>(
        &self,
        graph: G,
        writer: &mut W,
    ) -> impl core::future::Future<Output = Result<(), GraphError>> + Send
    where
        G: GraphView,
        W: AsyncWriteExt + Unpin + Send;
}

#[derive(Debug)]
pub enum TripleSerializer {
    #[cfg(feature = "source_n_triples")]
    NTriples(self::n_triples::NTriplesSerializer),
    #[cfg(feature = "source_turtle")]
    Turtle(self::turtle::TurtleSerializer<BasicProfile>),
}

impl TripleSerializer {
    pub fn from_media_type(
        media_type: &str,
        assumed_base: Option<Iri>,
    ) -> Result<Self, SourceError> {
        debug!("Determining serializer for media type {}", media_type);
        match media_type {
            #[cfg(feature = "source_n_triples")]
            "application/n-triples" => {
                Ok(Self::NTriples(self::n_triples::NTriplesSerializer::new()))
            }
            #[cfg(feature = "source_turtle")]
            "text/turtle" => Ok(Self::Turtle(self::turtle::TurtleSerializer::new(
                Arc::new(BasicProfile::new().into()),
                assumed_base,
            ))),
            _ => Err(SourceError::UnsupportedSourceConfig),
        }
    }
    pub fn from_media_type_and_profile(
        media_type: &str,
        state: Arc<Mutex<BasicProfile>>,
        assumed_base: Option<Iri>,
    ) -> Result<TripleSerializer, SourceError> {
        debug!("Determining serializer for media type {}", media_type);
        match media_type {
            #[cfg(feature = "source_n_triples")]
            "application/n-triples" => {
                Ok(Self::NTriples(self::n_triples::NTriplesSerializer::new()))
            }
            #[cfg(feature = "source_turtle")]
            "text/turtle" => Ok(Self::Turtle(self::turtle::TurtleSerializer::new(
                state,
                assumed_base,
            ))),
            _ => Err(SourceError::UnsupportedSourceConfig),
        }
    }
}

impl GraphSerializer for TripleSerializer {
    async fn write_all<G, W>(&self, graph: G, writer: &mut W) -> Result<(), GraphError>
    where
        G: GraphView,
        W: AsyncWriteExt + Send + Unpin,
    {
        match self {
            #[cfg(feature = "source_n_triples")]
            Self::NTriples(serializer) => serializer.write_all(graph, writer).await,
            #[cfg(feature = "source_turtle")]
            Self::Turtle(serializer) => serializer.write_all(graph, writer).await,
            _ => unreachable!(),
        }
    }
}
