use proc_macro::TokenStream;
use quote::quote;
use syn::{Lit, Token, parse::Parser, parse_macro_input, punctuated::Punctuated};

extern crate proc_macro;

#[proc_macro]
pub fn entrypoint(_: TokenStream) -> TokenStream {
    quote! {
        eetoee::lazy_static::lazy_static! {
            static ref BROWSER: std::sync::Arc<std::sync::Mutex<Option<eetoee::chrome::Browser>>> = {
                #[cfg(debug_assertions)]
                let debug = false;

                #[cfg(not(debug_assertions))]
                let debug = true;

                #[cfg(debug_assertions)]
                let args = vec![];

                #[cfg(not(debug_assertions))]
                let args = vec![
                    std::ffi::OsStr::new("--no-sandbox"),
                    std::ffi::OsStr::new("--disable-gpu"),
                    std::ffi::OsStr::new("--headless=new"),
                    std::ffi::OsStr::new("--disable-dev-shm-usage"),
                ];

                let options = eetoee::chrome::LaunchOptions {
                    headless: debug,
                    idle_browser_timeout: std::time::Duration::from_secs(60),
                    sandbox: !debug,
                    args,
                    ..Default::default()
                };

                std::sync::Arc::new(std::sync::Mutex::new(Some(eetoee::chrome::Browser::new(options).expect("Failed to create browser"))))
            };
        }

        fn main() {
            eetoee::run();
            *BROWSER.lock().expect("Failed to lock browser") = None;
        }
    }.into()
}

#[proc_macro_attribute]
pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as syn::ItemFn);
    let fn_name = &input.sig.ident;

    let args = Punctuated::<Lit, Token![,]>::parse_terminated
        .parse(attr)
        .expect("Failed to parse attribute args");

    let path = if let Some(Lit::Str(lit_str)) = args.first() {
        lit_str.value()
    } else {
        panic!("Expected a string literal with a path to concrete page");
    };

    quote! {
        #input

        eetoee::inventory::submit! {
            eetoee::Test { path: #path, runnable: |base_url| {
                let browser = BROWSER.lock().expect("Failed to lock browser");

                let Some(browser) = browser.as_ref() else {
                    panic!("Failed to lock browser");
                };

                let tab = browser.new_tab().expect("Failed to create new tab");
                let url = format!("{}{}", base_url, #path);

                tab.navigate_to(&url).expect("Failed to navigate to given URL");
                let _ = tab.wait_until_navigated();
                #fn_name(Arc::clone(&tab));
                tab.close(false).expect("Failed to close tab");
            }, name: stringify!(#fn_name) }
        }
    }
    .into()
}
