extern crate core;

use std::rc::Rc;

use crate::antlr::hamelinparser::{
    ExpressionEOFContextAll, HamelintypeContextAll, PipelineEOFContextAll, QueryContextAll,
    QueryEOFContextAll, QueryEOFContextAttrs,
};
use crate::err::{Context, TranslationError, TranslationErrors};
use crate::parser::{make_hamelin_parser_from_input, HamelinStringParser};
use antlr::hamelinparser::{
    CommandContextAll, CommandEOFContextAttrs, ExpressionContextAll, ExpressionEOFContextAttrs,
    IdentifierContextAll, IdentifierEOFContextAll, IdentifierEOFContextAttrs,
    SimpleIdentifierContextAll, SimpleIdentifierEOFContextAttrs,
};
use antlr_rust::errors::ANTLRError;
use anyhow::anyhow;

pub mod antlr;
pub mod catalog;
pub mod completion;
pub mod err;
pub mod func;
pub mod interner;
pub mod operator;
pub mod parser;
pub mod provider;
pub mod sql;
pub mod translation;
pub mod tree;
pub mod types;
mod write_utils;

pub const VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn execute_resillient_parse<T>(
    input: String,
    parse_fn: fn(HamelinStringParser) -> Result<T, ANTLRError>,
) -> anyhow::Result<(T, TranslationErrors)> {
    let (node, errors) = {
        let (parser, errors) = make_hamelin_parser_from_input(input);
        parse_fn(parser)
            .map_err(|e| anyhow!(e.to_string()))
            .map(|node| (node, errors))?
    };
    let unwrapped = Rc::try_unwrap(errors)
        .expect("could not unwrap Rc<TranslationErrors> after parsing complete.")
        .into_inner();
    Ok((node, unwrapped))
}

pub fn execute_parse<T>(
    input: String,
    parse_fn: fn(HamelinStringParser) -> Result<T, ANTLRError>,
) -> Result<T, TranslationErrors> {
    let len = input.len();
    let (node, errors) = {
        let (parser, errors) = make_hamelin_parser_from_input(input);
        parse_fn(parser)
            .map_err(|e| {
                TranslationError::new(Context::new(0..=len - 1, "failed to load grammars"))
                    .with_source_boxed(e.to_string().into())
                    .single()
            })
            .map(|node| (node, errors))?
    };
    let unwrapped = Rc::try_unwrap(errors)
        .expect("could not unwrap Rc<TranslationErrors> after parsing complete.")
        .into_inner();
    unwrapped.or_ok(node)
}

pub fn parse_command(command: String) -> Result<Rc<CommandContextAll<'static>>, TranslationErrors> {
    execute_parse(command, |mut parser| parser.commandEOF())
        .map(|ctx| ctx.command().expect("required"))
}

pub fn parse_query(statement: String) -> Result<Rc<QueryContextAll<'static>>, TranslationErrors> {
    execute_parse(statement, |mut parser| parser.queryEOF())
        .map(|ctx| ctx.query().expect("required"))
}

pub fn resilient_parse_query(
    statement: String,
) -> anyhow::Result<(Rc<QueryEOFContextAll<'static>>, TranslationErrors)> {
    execute_resillient_parse(statement, |mut parser| parser.queryEOF())
}

pub fn parse_expression(
    expression: String,
) -> Result<Rc<ExpressionContextAll<'static>>, TranslationErrors> {
    execute_parse(expression, |mut parser| parser.expressionEOF())
        .map(|ctx| ctx.expression().expect("required"))
}

pub fn resilient_parse_expression(
    expression: String,
) -> anyhow::Result<(Rc<ExpressionEOFContextAll<'static>>, TranslationErrors)> {
    execute_resillient_parse(expression, |mut parser| parser.expressionEOF())
}

pub fn resilient_parse_pipeline(
    pipeline: String,
) -> anyhow::Result<(Rc<PipelineEOFContextAll<'static>>, TranslationErrors)> {
    execute_resillient_parse(pipeline, |mut parser| parser.pipelineEOF())
}

pub fn parse_identifier(
    identifier: String,
) -> Result<Rc<IdentifierContextAll<'static>>, TranslationErrors> {
    execute_parse(identifier, |mut parser| parser.identifierEOF())
        .map(|ctx| ctx.identifier().expect("required"))
}

pub fn resilient_parse_identifier(
    identifier: String,
) -> anyhow::Result<(Rc<IdentifierEOFContextAll<'static>>, TranslationErrors)> {
    execute_resillient_parse(identifier, |mut parser| parser.identifierEOF())
}

pub fn parse_simple_identifier(
    identifier: String,
) -> Result<Rc<SimpleIdentifierContextAll<'static>>, TranslationErrors> {
    execute_parse(identifier, |mut parser| parser.simpleIdentifierEOF())
        .map(|ctx| ctx.simpleIdentifier().expect("required"))
}

pub fn parse_type(
    type_string: String,
) -> Result<Rc<HamelintypeContextAll<'static>>, TranslationErrors> {
    execute_parse(type_string, |mut parser| parser.hamelintype())
}
