pub(crate) mod custom_base_path;
pub(crate) mod repo_include_str;
pub(crate) mod repo_path;

use std::path::{Path, PathBuf};

use proc_macro2::{Span, TokenStream};
use syn::ExprLit;


fn parse_relative_path(base_path: PathBuf, relative_path: Option<&ExprLit>) -> syn::Result<PathBuf> {

    let relative_path = relative_path
        .map(parse_path_from_expr_lit)
        .transpose()?;

    let repo_dir = repo_path_lib::repo_dir();
    let path = crate::path::construct_and_validate_path(&repo_dir, &base_path, relative_path)?;

    Ok(path)
}


fn parse_path_from_expr_lit(expr_lit: &ExprLit) -> Result<(PathBuf, proc_macro2::Span), syn::Error> {
    match &expr_lit.lit {
        syn::Lit::Str(lit_str) => Ok((PathBuf::from(lit_str.value()), expr_lit.lit.span())),

        _ => Err(syn::Error::new_spanned(expr_lit, "Path needs to be specified as a string.")),
    }
}

/// Convert path to string, e.g. to allow passing as token into user-code.
fn convert_path_to_string(path: &Path, span: Span) -> syn::Result<&str> {
    match path.to_str() {
        Some(path_string) => Ok(path_string),
        None => Err(syn::Error::new(span, "Cannot convert path to valid UTF-8.")),
    }
}

fn quote_path_buf(path: PathBuf, span: Span) -> syn::Result<TokenStream> {
    let path = convert_path_to_string(&path, span)?;
    Ok(quote::quote_spanned! { span =>
        ::std::path::PathBuf::from(#path)
    })
}
