#![allow(clippy::upper_case_acronyms)] // << generated by pest.

use pest::Parser as _;
use pest_derive::Parser;
use rdftk_core::error::Error;
use rdftk_core::model::data_set::DataSet;
use rdftk_core::model::graph::Graph;
use tracing::{span, Level};

// ------------------------------------------------------------------------------------------------
// Public Macros
// ------------------------------------------------------------------------------------------------

#[macro_export]
macro_rules! make_factory_options {
    ($opt_name:ident, $factory_type:ty, $default_fn:ident) => {
        #[derive(Debug)]
        pub struct $opt_name {
            factory: $factory_type,
        }

        impl Default for $opt_name {
            fn default() -> Self {
                Self {
                    factory: $default_fn(),
                }
            }
        }

        impl $opt_name {
            pub fn with_factory(self, factory: $factory_type) -> Self {
                let mut self_mut = self;
                self_mut.factory = factory;
                self_mut
            }

            pub fn set_factory(&mut self, factory: $factory_type) {
                self.factory = factory;
            }

            pub fn factory(&self) -> &$factory_type {
                &self.factory
            }
        }
    };
}

macro_rules! parse_rule {
    ($rule_fn:literal entry $pair:expr) => {
        const RULE_FN: &'static str = $rule_fn;
        ::tracing::trace!("{}({:?}, ...)", $rule_fn, &$pair.as_rule());
    };
}

macro_rules! pest_error {
    (unexpected $rule_fn:expr, $given:expr, $expecting: expr ) => {
        ::rdftk_core::error::Error::ParserUnexpected {
            rule_fn: $rule_fn.into(),
            given: format!("{:?}", $given.as_rule()),
            expecting: $expecting.iter().map(|r| format!("{r:?}")).collect(),
        }
    };
}

// ------------------------------------------------------------------------------------------------
// Public Functions
// ------------------------------------------------------------------------------------------------

pub(crate) fn parse_ntriple_doc<S>(source: S) -> Result<Graph, Error>
where
    S: AsRef<str>,
{
    let span = span!(Level::TRACE, "NTriples");
    let _guard = span.enter();
    let mut parsed =
        CommonParser::parse(Rule::ntripleDoc, source.as_ref()).map_err(|e| Error::Tokenizer {
            representation: "NTriples".into(),
            source: Box::new(e),
        })?;
    let top_node = parsed.next().unwrap();
    ntriples::parse_doc(top_node)
}

pub(crate) fn parse_nquad_doc<S>(source: S) -> Result<DataSet, Error>
where
    S: AsRef<str>,
{
    let span = span!(Level::TRACE, "NQuads");
    let _guard = span.enter();
    let mut parsed =
        CommonParser::parse(Rule::nquadDoc, source.as_ref()).map_err(|e| Error::Tokenizer {
            representation: "NQuads".into(),
            source: Box::new(e),
        })?;
    let top_node = parsed.next().unwrap();
    nquads::parse_doc(top_node)
}

pub(crate) fn parse_turtle_doc<S>(_source: S) -> Result<Graph, Error>
where
    S: AsRef<str>,
{
    let span = span!(Level::TRACE, "Turtle");
    let _guard = span.enter();
    todo!()
}

pub(crate) fn parse_trig_doc<S>(_source: S) -> Result<DataSet, Error>
where
    S: AsRef<str>,
{
    let span = span!(Level::TRACE, "TRiG");
    let _guard = span.enter();
    todo!()
}

pub(crate) fn parse_n3_doc<S>(_source: S) -> Result<Graph, Error>
where
    S: AsRef<str>,
{
    let span = span!(Level::TRACE, "N3");
    let _guard = span.enter();
    todo!()
}

// ------------------------------------------------------------------------------------------------
// Private Types
// ------------------------------------------------------------------------------------------------

#[derive(Parser)]
#[grammar = "common/common.pest"]
struct CommonParser;

// ------------------------------------------------------------------------------------------------
// Modules
// ------------------------------------------------------------------------------------------------

mod ntriples;

mod nquads;

mod turtle;

mod trig;

mod n3;
