use {
    ariadne::{Color, Label, Report, ReportKind, Source},
    chumsky::{
        prelude::*, text::*
    }
};

#[derive(Debug)]
struct Morphism {
    symbol: String,
    src_type: String,
    dst_type: String,
    type_args: Vec<(String, String)>,
    locations: Vec<String>
}

/* morphism-base text format:
 *     NAME '(' [TYPE-ARG-NAME ':' KIND]  ')'
 *           SRC-TYPE
 *     '-->' DST-TYPE
 *     '@' [ LOCATION ':' ]
 */
fn parser() -> impl Parser<char, Vec<Morphism>, Error = Simple<char>> {
    ident().padded()
    .then(
        ident().padded()
        .then_ignore(just(':').padded())
        .then(none_of(",)").repeated().padded())
        .separated_by(just(',').padded())
        .delimited_by(just('('), just(')'))
    )
    .then_ignore(just('\n'))
    .then(
        take_until(just("-->").ignored())
        .then(take_until(just('@').ignored()))
    )
    .then(
        none_of(":\n").repeated().separated_by(just(':'))
    )
    .map(|(((symbol, type_args), ((src_type, _), (dst_type, _))), locations)| {
        Morphism {
            symbol,
            src_type: src_type.iter().collect(),
            dst_type: dst_type.iter().collect(),
            type_args: type_args.into_iter().map(|(v,k)| (v,k.into_iter().collect())).collect(),
            locations: locations.into_iter().map(|l| l.into_iter().collect()).collect()
        }
    })
    .separated_by(text::newline())
}

fn main() {
    println!("Hello, world!");

    let src = "
        morph_digit_as_char_to_uint8 (Radix:ℤ_16)
            <Digit Radix> ~ Char ~ Ascii ~ Byte
        --> <Digit Radix> ~ x86.UInt8 ~ Byte
        @lib/libmorph_posint.so:src/posint.c

        morph_string_as_nullterm_to_length_prefix ()
            [~<ValueDelim '\0'> Char ~ Ascii]
        --> [~<LengthPrefix x86.UInt64> Char ~ Ascii]
        @lib/libmorph_length-prefix.so:src/length_prefix.c

        morph_string_as_length_prefix_to_nullterm ()
            [~<LengthPrefix x86.UInt64> Char ~ Ascii]
        --> [~<ValueDelim '\0'> Char ~ Ascii]
        @lib/libmorph_length-prefix.so:src/length_prefix.c
    ";

    let result = parser().parse(src);

    match result {
        Ok(morphisms) => {
            println!("parse ok.\n{:?}", morphisms);
        }
        Err(errs) => {
            errs.into_iter().for_each(|e| {
                    Report::build(ReportKind::Error, (), e.span().start)
                        .with_message(e.to_string())
                        .with_label(
                            Label::new(e.span())
                                .with_message(e)
                                .with_color(Color::Red),
                        )
                        .finish()
                        .print(Source::from(&src))
                        .unwrap()
                    });
        }
    }
}