use proc_macro2::Ident;
use quote::format_ident;

use crate::parse::{
    options::{FieldExtract, FieldExtractStep, ParseVariant},
    parse_utility::parse_field_source_extract,
};

pub fn get_variant_extract(variant: &ParseVariant) -> syn::Result<FieldExtract> {
    let target_ident = &variant.ident;
    let mut steps = if let Some(source) = variant.options.source.as_ref() {
        let mut source_extract = parse_field_source_extract(source)
            .ok_or_else(|| syn::Error::new_spanned(target_ident, "invalid source"))?;
        if !source_extract.steps.is_empty() {
            source_extract.steps.remove(0);
        }
        source_extract.steps
    } else {
        Vec::new()
    };

    if let Some(extract) = variant.options.extract.clone() {
        steps.extend(extract.steps);
    }

    if let Some(field_type_info) = variant.type_info.as_ref()
        && variant.options.extract.is_none()
        && variant.options.source.is_none()
        && variant.options.derive.is_none()
        && !variant.options.oneof
        && !variant.options.enumeration
    {
        if field_type_info.container_ident.as_deref() == Some("Option") {
            steps.push(FieldExtractStep::Unwrap);
        }
        if field_type_info.container_ident.as_deref() == Some("Box") {
            steps.push(FieldExtractStep::Unbox);
        }
    }

    Ok(FieldExtract { steps })
}

pub fn get_variant_source_ident(variant: &ParseVariant) -> syn::Result<Ident> {
    Ok(
        if let Some(variant_source) = variant.options.source.as_ref() {
            if variant_source.contains('.') || variant_source.contains('?') {
                format_ident!(
                    "{}",
                    variant_source
                        .split('.')
                        .next()
                        .map(|part| part.trim_matches('?'))
                        .ok_or_else(|| syn::Error::new_spanned(&variant.ident, "invalid source"))?
                )
            } else {
                format_ident!("{}", variant_source)
            }
        } else {
            variant.ident.clone()
        },
    )
}
