use std::{collections::HashMap, sync::LazyLock};

use nom::{
    IResult, Parser,
    branch::alt,
    character::complete::{anychar, line_ending, not_line_ending, space0},
    combinator::{eof, not, recognize},
    multi::{many0, many1},
    sequence::{preceded, terminated},
};

pub(super) static ENTITIES: LazyLock<HashMap<String, &'static entities::Entity>> =
    LazyLock::new(|| {
        let mut map = HashMap::new();
        for entity in &entities::ENTITIES {
            map.insert(entity.entity.to_string(), entity);
        }
        map
    });

pub(super) fn eof_or_eol(input: &str) -> IResult<&str, &str> {
    alt((line_ending, eof)).parse(input)
}

pub(super) fn many_empty_lines0(input: &str) -> IResult<&str, Vec<&str>> {
    many0(preceded(space0, eof_or_eol)).parse(input)
}

pub(super) fn not_eof_or_eol1(input: &str) -> IResult<&str, &str> {
    recognize(many1(preceded(not(eof_or_eol), anychar))).parse(input)
}

pub(super) fn not_eof_or_eol0(input: &str) -> IResult<&str, &str> {
    alt((not_line_ending, eof)).parse(input)
}

pub(super) fn line_terminated<'a, O, P>(
    inner: P,
) -> impl Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>
where
    P: Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>,
{
    terminated(inner, eof_or_eol)
}

// pub(crate) fn logged<'a, O, P>(
//     message: &'static str,
//     mut inner: P,
// ) -> impl Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>
// where
//     P: Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>,
//     O: std::fmt::Debug,
// {
//     move |input: &'a str| {
//         println!("Logged: {message}: {:?}", input);
//         let r = inner.parse(input);
//         println!("Logged out: {message}: {:?}", r);
//         r
//     }
// }
