#![recursion_limit="4096"]

extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};

use proc_macro::TokenTree::Group;

use std::convert::TryFrom;
use litrs::{CharLit, StringLit};
use quote::quote;

#[proc_macro]
pub fn print_tokens(input: TokenStream) -> TokenStream {
    println!("{}", input);
    input
}


#[proc_macro]
pub fn parse_literal(input: TokenStream) -> TokenStream {

    let mut input_parsed: Vec<TokenTree> = input.clone().into_iter().collect();
    if input_parsed.len() != 1 {
        panic!("expected one token only!");
    }

    match input_parsed.remove(0) {
        Group(g) => {
            let mut token_tree: Vec<TokenTree> = g.stream().clone().into_iter().collect();
            let token = token_tree.remove(0);
            let token_copy = token.clone();
            let token_copy_copy = token.clone();
            match CharLit::try_from(token) {
                Ok(c) => {
                    let c_val = c.value();
                    let stream: proc_macro::TokenStream = TokenStream::from(quote!(
                        char(#c_val)
                    ));
                    return stream;
                },
                _ => {}
            }

            match StringLit::try_from(token_copy) {
                Ok(s) => {
                    let v = s.value().to_string();

                    let crs = s.value().clone().chars().collect::<Vec<char>>().into_iter().rev()
                        .fold(quote!(pure #v), |acc, i| quote!(#i *> #acc));

                    return TokenStream::from(quote!(parser!(#crs)));

                },
                _ => {}
            }

            match token_copy_copy {
                Group(g) => {
                    let mut token_tree: Vec<TokenTree> = g.stream().clone().into_iter().collect();
                    let token = token_tree.remove(0);
                    let token_copy = token.clone();
                    match CharLit::try_from(token) {
                        Ok(c) => {
                            let c_val = c.value();
                            let stream: proc_macro::TokenStream = TokenStream::from(quote!(
                                char(#c_val)
                            ));
                            return stream;
                        },
                        _ => {}
                    }
        
                    match StringLit::try_from(token_copy) {
                        Ok(s) => {
                            let v = s.value().to_string();
                            let crs = s.value().clone().chars().collect::<Vec<char>>().into_iter().rev()
                                .fold(quote!(pure #v), |acc, i| quote!(#i *> #acc));
        
                            return TokenStream::from(quote!(parser!(#crs)));
        
                        },
                        _ => {}
                    }
                },
                _ => {}
            }
        },
        _ => {}
    }
    

    input
}