/// `"/"  path_segments`
pub fn abs_path(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(nom::bytes::complete::tag("/"), crate::parsers::component::path_segments)(i)
}

/// `reg_name | server`
pub fn authority(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((crate::parsers::multi_char::reg_name, crate::parsers::component::server))(i)
}

/// `alpanum | alphanum *( alphanum | "-" ) alphanum`
pub fn domain_label(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::multi::separated_list1(
        nom::multi::many1_count(nom::bytes::complete::tag("-")),
        nom::character::complete::alphanumeric1,
    ))(i)
}

/// `( net_path | abs_path ) [ "?" query ]`
pub fn hier_part(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        nom::branch::alt((crate::parsers::component::net_path, crate::parsers::component::abs_path)),
        nom::combinator::opt(nom::sequence::pair(nom::bytes::complete::tag("?"), crate::parsers::multi_char::query)),
    )(i)
}

/// `hostname | IPv4address`
pub fn host(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((crate::parsers::component::hostname, crate::parsers::component::ipv4_address))(i)
}

/// `*( domainlabel "." ) toplabel [ "." ]`
pub fn hostname(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_tuple((
        nom::multi::many0_count(nom::sequence::tuple((
            crate::parsers::component::domain_label,
            nom::bytes::complete::tag("."),
            nom::combinator::peek(crate::parsers::component::top_label),
        ))),
        crate::parsers::component::top_label,
        nom::combinator::opt(nom::bytes::complete::tag(".")),
    ))(i)
}

/// `host [ ":" port ]`
pub fn host_port(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        crate::parsers::component::host,
        nom::combinator::opt(nom::sequence::pair(nom::bytes::complete::tag(":"), crate::parsers::multi_char::port)),
    )(i)
}

/// `1*digit "." 1*digit "." 1*digit "." 1*digit`
pub fn ipv4_address(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_tuple((
        nom::character::complete::digit1,
        nom::bytes::complete::tag("."),
        nom::character::complete::digit1,
        nom::bytes::complete::tag("."),
        nom::character::complete::digit1,
        nom::bytes::complete::tag("."),
        nom::character::complete::digit1,
    ))(i)
}

/// `"//" authority [ abs_path ]`
pub fn net_path(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_tuple((
        nom::bytes::complete::tag("//"),
        crate::parsers::component::authority,
        nom::combinator::opt(crate::parsers::component::abs_path),
    ))(i)
}

/// `uric_no_slash *uric`
pub fn opaque_part(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_tuple((
        crate::parsers::char::uri_c_no_slash,
        nom::multi::many0_count(crate::parsers::char::uri_c),
    ))(i)
}

/// `segment *( "/" segment )`
pub fn path_segments(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        crate::parsers::component::segment,
        nom::multi::many0_count(nom::sequence::pair(
            nom::bytes::complete::tag("/"),
            crate::parsers::component::segment,
        )),
    )(i)
}

/// `rel_segment [ abs_path ]`
pub fn rel_path(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        crate::parsers::multi_char::rel_segment,
        nom::combinator::opt(crate::parsers::component::abs_path),
    )(i)
}

/// `alpha *( alpha | digit | "+" | "-" | "." )`
pub fn scheme(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        crate::parsers::char::alpha,
        nom::bytes::complete::take_while(|c: char| c.is_ascii_alphanumeric() || matches!(c, '+' | '-' | '.')),
    )(i)
}

/// `*pchar *( ";" param )`
pub fn segment(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        nom::multi::many0_count(crate::parsers::char::p_char),
        nom::multi::many0_count(nom::sequence::pair(nom::bytes::complete::tag(";"), crate::parsers::multi_char::param)),
    )(i)
}

/// `[ [ userinfo "@" ] hostport ]`
pub fn server(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::combinator::opt(nom::sequence::pair(
        nom::combinator::opt(nom::sequence::pair(
            crate::parsers::multi_char::user_info,
            nom::bytes::complete::tag("@"),
        )),
        crate::parsers::component::host_port,
    )))(i)
}

/// `alpha | alpha *( alphanum | "-" ) alphanum`
pub fn top_label(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_pair(
        nom::combinator::peek(crate::parsers::char::alpha),
        nom::multi::separated_list1(
            nom::multi::many1_count(nom::bytes::complete::tag("-")),
            nom::character::complete::alphanumeric1,
        ),
    )(i)
}

#[cfg(test)]
mod abs_path {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/abs_path_tests.rs"));
}

#[cfg(test)]
mod authority {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/authority_tests.rs"));
}

#[cfg(test)]
mod domain_label {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/domain_label_tests.rs"));
}

#[cfg(test)]
mod hier_part {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/hier_part_tests.rs"));
}

#[cfg(test)]
mod host {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/host_tests.rs"));
}

#[cfg(test)]
mod hostname {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/hostname_tests.rs"));
}

#[cfg(test)]
mod ipv4_address {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/ipv4_address_tests.rs"));
}

#[cfg(test)]
mod net_path {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/net_path_tests.rs"));
}

#[cfg(test)]
mod opaque_part {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/opaque_part_tests.rs"));
}

#[cfg(test)]
mod path_segments {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/path_segments_tests.rs"));
}

#[cfg(test)]
mod rel_path {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/rel_path_tests.rs"));
}

#[cfg(test)]
mod scheme {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/scheme_tests.rs"));
}

#[cfg(test)]
mod segment {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/segment_tests.rs"));
}

#[cfg(test)]
mod server {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/server_tests.rs"));
}

#[cfg(test)]
mod top_label {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/top_label_tests.rs"));
}
