#![allow(non_snake_case)]

use darling::FromDeriveInput;
use indexmap::{IndexMap, IndexSet};
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{format_ident, quote};
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::{Data, Error, Expr, Generics, Ident, Path};
use syn::{
    DataEnum, DeriveInput, Fields, GenericArgument, PathArguments,
    Result as SynResult, Token, Type, TypePath, WhereClause, braced, bracketed,
    parse::Parse, parse_macro_input, parse_quote,
};

use crate::dtype_variant_path;
use crate::matcher_gen::{MacroRuleArm, generate_macro_rule_arm};

/// Parses the top-level `#[dtype(...)]` attribute applied to the enum.
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(dtype), supports(enum_any))] // Specify attribute name and support only enums
struct DTypeMacroArgs {
    /// The identifier of the enum (e.g., `MyEnum`).
    ident: Ident,
    /// The generic parameters of the enum (e.g., `<'a, T: Bound>`).
    generics: Generics,
    /// The body of the enum (variants and fields).
    /// Uses darling::ast::Data for potential future integration with variant/field attributes.
    // data: DarlingData<NestedVariant, NestedField>,

    // --- Configuration Fields ---
    /// **Required.** Path to the module/enum generated by `build_dtype_tokens`.
    /// Example: `"my_crate::tokens::MyTokens"`
    #[darling(default)]
    tokens_path: Option<Path>,

    /// Optional. Identifier of the container type wrapping variant payloads.
    /// Example: `"Vec"`, `"Box"`
    #[darling(default)]
    container: Option<Ident>,

    /// Optional. Path to a trait that inner types of variants must implement.
    /// Example: `"my_crate::constraints::MyConstraint"`
    #[darling(default)]
    constraint: Option<Expr>,

    /// Optional. Identifier for the name of the generated closure-based matcher method.
    /// Example: `"match_variant"`
    #[darling(default)]
    matcher: Option<Ident>,

    /// Optional. Defines a grouped matcher macro.
    /// Format: `"macro_name, { Numeric: [VariantA, VariantB], UnitLike: [VariantC] }"`
    #[darling(default)]
    grouped_matcher: Option<String>,

    /// Optional. If true, skips generating From impls for the enum variants.
    #[darling(default)]
    skip_from_impls: bool,
}

#[derive(Debug, Clone)]
pub struct ParsedVariantInfo {
    /// Identifier of the enum variant (e.g., `MyVariant`).
    pub variant_ident: Ident,
    /// Identifier of the corresponding token (e.g., `MyVariantVariant`).
    pub token_ident: Ident,
    /// The full type of the field in a tuple variant (e.g., `Vec<u16>` or `f64`).
    /// `None` for unit variants.
    pub full_field_type: Option<Type>,
    /// The inner payload type (e.g., `u16` from `Vec<u16>`, or `f64` if no container).
    /// `None` for unit variants.
    pub inner_type: Option<Type>,
    /// True if this is a unit variant (e.g., `MyUnitVariant`).
    pub is_unit: bool,
}

// In ParsedGroupedMatcher definition:
#[derive(Debug, Clone)]
struct ParsedGroupedMatcher {
    macro_name: Ident,
    /// Vector of groups: (GroupName, Vec<VariantIdent>)
    groups: Vec<(Ident, Vec<Ident>)>, // Changed from Vec<Vec<Ident>>
    _span: Span,
}

pub fn dtype_derive_impl(input: TokenStream) -> TokenStream {
    let dtype_variant_path = dtype_variant_path();

    // Parse the input token stream into a syn::DeriveInput AST node.
    let derive_input = parse_macro_input!(input as DeriveInput);

    // Parse the #[dtype(...)] attributes using darling.
    let args = match DTypeMacroArgs::from_derive_input(&derive_input) {
        Ok(args) => args,
        Err(e) => return e.write_errors().into(),
    };

    // Perform initial validation: ensure it's an enum.
    let enum_data = match &derive_input.data {
        Data::Enum(data) => data,
        _ => {
            return Error::new_spanned(
                &derive_input.ident,
                "DTypeEnum derive macro can only be used on enums.",
            )
            .to_compile_error()
            .into();
        }
    };

    // Parse string paths from darling config into syn types.
    let parse_result = parse_config_paths(&args);
    let ParsedPaths {
        tokens_path_opt,
        container_ident_opt,
        constraint_path_opt,
        matcher_ident_opt,
    } = match parse_result {
        Ok(paths) => paths,
        Err(e) => return e.to_compile_error().into(),
    };

    // Validate required 'tokens' path is present.
    let tokens_path = match tokens_path_opt {
        Some(path) => path,
        None => {
            return Error::new_spanned(
                &derive_input.ident,
                "Missing required `tokens` attribute path in #[dtype(...)]. \
                     Specify the path to the module generated by `build_dtype_tokens`.",
            )
            .to_compile_error()
            .into();
        }
    };

    // Parse enum variants and extract necessary info.
    let variant_parse_result = parse_variants(enum_data, &container_ident_opt);
    let parsed_variants = match variant_parse_result {
        Ok(variants) => variants,
        Err(e) => return e.to_compile_error().into(),
    };

    // Parse the grouped_matcher attribute string.
    let grouped_matcher_parse_result =
        parse_grouped_matcher_string(&args.grouped_matcher, args.ident.span());
    let parsed_grouped_matcher_opt = match grouped_matcher_parse_result {
        Ok(opt) => opt,
        Err(e) => return e.to_compile_error().into(),
    };

    // Validate the grouped matcher definition against parsed variants.
    if let Some(ref parsed_grouped_matcher) = parsed_grouped_matcher_opt {
        if let Err(e) =
            validate_grouped_matcher(parsed_grouped_matcher, &parsed_variants)
        {
            return e.to_compile_error().into();
        }
    }

    // Extract components for code generation.
    let enum_name = &args.ident;
    let generics = &args.generics;

    // Generate the different code blocks using helper functions.
    let token_validation_code =
        generate_token_validation(&tokens_path, &parsed_variants);
    let target_impls = generate_enum_variant_downcast(
        &dtype_variant_path,
        enum_name,
        generics,
        &parsed_variants,
        &tokens_path,
    );
    let constraint_impls = generate_enum_variant_constraint(
        &dtype_variant_path,
        enum_name,
        generics,
        &parsed_variants,
        &constraint_path_opt,
        &tokens_path, // Pass tokens_path
    );
    let from_impls = generate_from_impls(
        enum_name,
        generics,
        &parsed_variants,
        container_ident_opt.is_some(),
        &tokens_path,
        args.skip_from_impls,
    );
    let downcast_methods = generate_downcast_methods(
        &dtype_variant_path,
        enum_name,
        generics,
        &parsed_variants,
    );
    let matcher_method = generate_matcher_method(
        &dtype_variant_path,
        enum_name,
        generics,
        &parsed_variants,
        &matcher_ident_opt,
        &tokens_path,
    );
    let grouped_matcher_macro = generate_grouped_matcher_macro(
        &dtype_variant_path,
        enum_name,
        generics, // Pass generics
        &parsed_variants,
        &parsed_grouped_matcher_opt,
        &tokens_path,
    );

    // Combine generated code fragments.
    let final_code = quote! {
        // Compile-time validation of token existence.
        #token_validation_code

        // Implementations of #dtype_variant_path::EnumVariantTarget trait.
        #target_impls

        // Implementations of the user-specified constraint trait.
        #constraint_impls

        // Implementations of From<PayloadType> for the enum.
        #from_impls

        // Implementation block containing downcast methods.
        #downcast_methods

        // Implementation block containing the matcher method.
        #matcher_method

        // Implementation block containing the grouped matcher macro.
        #grouped_matcher_macro
    };

    // Return the final generated code.
    final_code.into()
}

//----------------------------------------------------------------------------
// 4. Helper Functions for Parsing and Validation
//----------------------------------------------------------------------------

/// Parses string paths/identifiers from the darling config struct into syn types.
#[derive(Default)]
struct ParsedPaths {
    tokens_path_opt: Option<Path>,
    container_ident_opt: Option<Ident>,
    constraint_path_opt: Option<Expr>,
    matcher_ident_opt: Option<Ident>,
}

fn parse_config_paths(args: &DTypeMacroArgs) -> Result<ParsedPaths, Error> {
    let tokens_path: Option<Path> = args.tokens_path.clone();
    let container_ident: Option<Ident> = args.container.clone();
    let constraint_path: Option<Expr> = args.constraint.clone();
    let matcher_ident: Option<Ident> = args.matcher.clone();

    Ok(ParsedPaths {
        tokens_path_opt: tokens_path,
        container_ident_opt: container_ident,
        constraint_path_opt: constraint_path,
        matcher_ident_opt: matcher_ident,
    })
}
/// Parses enum variants, extracting types and validating structure.
fn parse_variants(
    enum_data: &DataEnum,
    container_ident: &Option<Ident>,
) -> Result<Vec<ParsedVariantInfo>, Error> {
    let mut variants_info = Vec::new();

    for variant in &enum_data.variants {
        let variant_ident = variant.ident.clone();
        // Assume token identifier is VariantNameVariant (adjust if needed).
        let token_ident = format_ident!(
            "{}Variant",
            variant_ident,
            span = variant_ident.span()
        );

        match &variant.fields {
            Fields::Unit => {
                variants_info.push(ParsedVariantInfo {
                    variant_ident,
                    token_ident,
                    full_field_type: None,
                    inner_type: None,
                    is_unit: true,
                });
            }
            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
                let field = fields.unnamed.first().unwrap();
                let full_field_type = field.ty.clone();
                let inner_type =
                    extract_inner_type(&full_field_type, container_ident)?;

                variants_info.push(ParsedVariantInfo {
                    variant_ident,
                    token_ident,
                    full_field_type: Some(full_field_type),
                    inner_type: Some(inner_type),
                    is_unit: false,
                });
            }
            Fields::Named(_) => {
                return Err(Error::new_spanned(
                    &variant.fields,
                    "DTypeEnum does not support variants with named fields.",
                ));
            }
            Fields::Unnamed(_) => {
                return Err(Error::new_spanned(
                    &variant.fields,
                    "DTypeEnum only supports tuple variants with exactly one field.",
                ));
            }
        }
    }
    Ok(variants_info)
}

/// Helper function to extract the inner type from a container type
fn extract_inner_type(
    full_field_type: &Type,
    container_ident: &Option<Ident>,
) -> Result<Type, Error> {
    if let Some(container) = container_ident {
        // Attempt to extract T from Container<T>
        if let Type::Path(TypePath { path, .. }) = &full_field_type {
            if let Some(segment) = path.segments.last() {
                if segment.ident == *container {
                    if let PathArguments::AngleBracketed(args) =
                        &segment.arguments
                    {
                        if args.args.len() == 1 {
                            if let Some(GenericArgument::Type(ty)) =
                                args.args.first()
                            {
                                Ok(ty.clone())
                            } else {
                                Err(Error::new_spanned(
                                    args,
                                    "Container expects a type argument",
                                ))
                            }
                        } else {
                            Err(Error::new_spanned(
                                args,
                                "Container expects exactly one type argument",
                            ))
                        }
                    } else {
                        Err(Error::new_spanned(
                            segment,
                            "Container expects angle bracketed arguments",
                        ))
                    }
                } else {
                    Err(Error::new_spanned(
                        segment,
                        format!(
                            "Expected container type `{}`, found `{}`",
                            container, segment.ident
                        ),
                    ))
                }
            } else {
                Err(Error::new_spanned(path, "Cannot get path segment"))
            }
        } else {
            Err(Error::new_spanned(
                full_field_type,
                format!(
                    "Expected a path type matching container `{}`",
                    container
                ),
            ))
        }
    } else {
        // No container specified, the full type is the inner type
        Ok(full_field_type.clone())
    }
}

/// Parses the string provided to `grouped_matcher`.
/// Format: "macro_name, { [VariantA, VariantB], [VariantC] }"
fn parse_grouped_matcher_string(
    grouped_matcher_str_opt: &Option<String>,
    fallback_span: Span,
) -> Result<Option<ParsedGroupedMatcher>, Error> {
    let Some(grouped_matcher_str) = grouped_matcher_str_opt else {
        return Ok(None);
    };

    // Use a custom parser to handle the specific format
    match syn::parse_str::<GroupedMatcherParser>(grouped_matcher_str) {
        Ok(parsed) => Ok(Some(ParsedGroupedMatcher {
            macro_name: parsed.macro_name,
            groups: parsed.groups,
            _span: fallback_span, // Use fallback span for now, better span info is hard from string
        })),
        Err(e) => Err(Error::new(
            fallback_span, // Associate error with the attribute/enum span
            format!(
                "Failed to parse `grouped_matcher` string \"{}\": {}",
                grouped_matcher_str, e
            ),
        )),
    }
}

// Helper struct for parsing the `grouped_matcher` string content using syn::parse.
// Format: macro_name, { GroupName1: [V1, V2], GroupName2: [V3, V4] }
struct GroupedMatcherParser {
    macro_name: Ident,
    groups: Vec<(Ident, Vec<Ident>)>, // Changed
}

impl Parse for GroupedMatcherParser {
    fn parse(input: ParseStream) -> SynResult<Self> {
        // 1. Parse Macro Name
        let macro_name: Ident = input.parse()?;

        // 2. Parse Comma Separator
        input.parse::<Token![,]>()?;

        // 3. Parse Groups within Braces {}
        let groups_content;
        braced!(groups_content in input);

        let mut groups = Vec::new();
        // Parse comma-separated list of named groups: GroupName: [VariantA, VariantB], ...
        while !groups_content.is_empty() {
            // Parse Group Name
            let group_name: Ident = groups_content.parse()?;

            // Parse Colon Separator
            groups_content.parse::<Token![:]>()?;

            // Parse Variants within Brackets []
            let variants_content;
            bracketed!(variants_content in groups_content);

            let variants_in_group: Punctuated<Ident, Token![,]> =
                variants_content.parse_terminated(Ident::parse, Token![,])?;

            if variants_in_group.is_empty() {
                return Err(Error::new(
                    variants_content.span(),
                    "Group cannot be empty",
                ));
            }

            groups.push((group_name, variants_in_group.into_iter().collect()));

            // Consume optional trailing comma or break if end
            if groups_content.is_empty() {
                break;
            }
            groups_content.parse::<Token![,]>()?; // Expect comma between groups
        }

        if groups.is_empty() {
            return Err(Error::new(
                input.span(),
                "Grouped matcher must define at least one group",
            ));
        }

        Ok(GroupedMatcherParser { macro_name, groups })
    }
}

/// Validates the parsed named grouped matcher against the enum variants.
fn validate_grouped_matcher(
    parsed_grouped_matcher: &ParsedGroupedMatcher,
    parsed_variants: &[ParsedVariantInfo],
) -> Result<(), Error> {
    let mut all_grouped_variants = IndexSet::new();
    let mut duplicate_variant_check = IndexSet::new();
    let mut duplicate_group_name_check = IndexSet::new();
    let valid_variant_names: IndexSet<_> = parsed_variants
        .iter()
        .map(|v| v.variant_ident.to_string())
        .collect();

    for (group_name, group_variants) in &parsed_grouped_matcher.groups {
        // Check for duplicate group names
        if !duplicate_group_name_check.insert(group_name.to_string()) {
            return Err(Error::new_spanned(
                group_name,
                format!(
                    "Duplicate group name `{}` found in `grouped_matcher` attribute",
                    group_name
                ),
            ));
        }

        for variant_ident in group_variants {
            let variant_name = variant_ident.to_string();

            // Check if variant exists in the enum
            if !valid_variant_names.contains(&variant_name) {
                return Err(Error::new_spanned(
                    variant_ident, // Point to the specific identifier in the attribute
                    format!(
                        "Variant `{}` in group `{}` does not exist in the enum",
                        variant_name, group_name
                    ),
                ));
            }

            // Check if variant is already listed in another group
            if !duplicate_variant_check.insert(variant_name.clone()) {
                return Err(Error::new_spanned(
                    variant_ident,
                    format!(
                        "Variant `{}` is listed in multiple groups (`{}` and potentially others)",
                        variant_name, group_name
                    ),
                ));
            }
            all_grouped_variants.insert(variant_name);
        }
    }

    // Check if all enum variants are covered by the groups
    for variant_info in parsed_variants {
        if !all_grouped_variants
            .contains(&variant_info.variant_ident.to_string())
        {
            return Err(Error::new_spanned(
                &variant_info.variant_ident, // Point to the enum variant definition
                format!(
                    "Enum variant `{}` is not included in any group in the `grouped_matcher` attribute",
                    variant_info.variant_ident
                ),
            ));
        }
    }

    Ok(())
}

//----------------------------------------------------------------------------
// 5. Helper Functions for Code Generation (`quote!`)
//----------------------------------------------------------------------------

/// Generates compile-time checks for token existence.
fn generate_token_validation(
    tokens_path: &Path,
    parsed_variants: &[ParsedVariantInfo],
) -> TokenStream2 {
    let validation_checks = parsed_variants.iter().map(|v| {
        let token_ident = &v.token_ident;
        // This code runs at compile time inside the const block.
        // If the path #tokens_path::#token_ident is invalid, compilation fails here.
        quote! { let _ = #tokens_path::#token_ident; }
    });

    quote! {
        // This const block forces compile-time evaluation of the checks inside.
        const _: () = {
            // Ensure the compiler knows about the crate containing the tokens.
            // This might require adjustment based on how tokens_path is structured.
            // use #tokens_path; // This might be too broad or incorrect depending on path structure

            #(#validation_checks)*
        };
    }
}

/// Generates `impl #dtype_variant_path::EnumVariantTarget<...>` blocks.
fn generate_enum_variant_downcast(
    dtype_variant_path: &Path,
    enum_name: &Ident,
    generics: &Generics,
    parsed_variants: &[ParsedVariantInfo],
    tokens_path: &Path, // Add tokens_path parameter
) -> TokenStream2 {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let downcast_impls = parsed_variants.iter().filter_map(|v| {
        if v.is_unit {
            return None;
        } // Skip unit variants
        let variant_ident = &v.variant_ident;
        let token_ident = &v.token_ident;
        let full_field_type = v.full_field_type.as_ref()?; // Should always be Some for non-unit

        // Add bounds ensuring the inner type and original lifetimes outlive the target lifetime
        let where_clause_with_bounds = where_clause.cloned().unwrap_or_else(|| WhereClause {
            where_token: Default::default(),
            predicates: Default::default(),
        });

        // Use the full path to the token
        Some(quote! {
            // Implement the new #dtype_variant_path::EnumVariantDowncast trait
            impl #impl_generics #dtype_variant_path::EnumVariantDowncast<#tokens_path::#token_ident>
                for #enum_name #ty_generics #where_clause_with_bounds
            {
                type Target = #full_field_type;

                fn downcast_ref(&self) -> Option<&Self::Target> {
                    match self {
                        Self::#variant_ident(field_payload) => Some(field_payload),
                        _ => None,
                    }
                }

                fn downcast_mut(&mut self) -> Option<&mut Self::Target> {
                    match self {
                        Self::#variant_ident(field_payload) => Some(field_payload),
                        _ => None,
                    }
                }

                fn downcast(self) -> Option<Self::Target> {
                    match self {
                        Self::#variant_ident(field_payload) => Some(field_payload),
                        _ => None,
                    }
                }
            }
        })
    });

    quote! { #(#downcast_impls)* }
}
/// Generates `impl #dtype_variant_path::EnumVariantConstraint<...>` blocks if `constraint` is specified.
fn generate_enum_variant_constraint(
    dtype_variant_path: &Path,
    enum_name: &Ident,
    generics: &Generics,
    parsed_variants: &[ParsedVariantInfo],
    constaint_opt: &Option<Expr>,
    tokens_path: &Path, // Add tokens_path parameter
) -> TokenStream2 {
    let constraint = match constaint_opt {
        Some(path) => path,
        None => return quote! {}, // No constraint specified
    };

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let constraint_impls = parsed_variants.iter().filter_map(|v| {
        if v.is_unit {
            return None;
        } // Skip unit variants
        let token_ident = &v.token_ident;
        let inner_type = v.inner_type.as_ref()?;

        // Add the constraint bound to the where clause
        let mut where_clause_with_bounds = where_clause.cloned().unwrap_or_else(|| WhereClause {
            where_token: Default::default(),
            predicates: Default::default(),
        });

        // Add constraint that inner_type implements the constraint_path
        where_clause_with_bounds
            .predicates
            .push(parse_quote!(#inner_type: #constraint));

        Some(quote! {
            // Implement #dtype_variant_path::EnumVariantConstraint for the enum with the token type
            // Use the full path to the token
            impl #impl_generics #dtype_variant_path::EnumVariantConstraint<#tokens_path::#token_ident>
                for #enum_name #ty_generics #where_clause_with_bounds
            {
                // Set the Constraint associated type to the inner type
                type Constraint = #inner_type;
            }
        })
    });

    quote! { #(#constraint_impls)* }
}

/// Generates `impl From<FieldType>` blocks.
fn generate_from_impls(
    enum_name: &Ident,
    generics: &Generics,
    parsed_variants: &[ParsedVariantInfo],
    has_container: bool,
    tokens_path: &Path,
    skip_from_impls: bool,
) -> TokenStream2 {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let payload_from_impls = parsed_variants.iter().filter_map(|v| {
        if v.is_unit {
            return None;
        } // Skip unit variants
        let variant_ident = &v.variant_ident;
        let full_field_type = v.full_field_type.as_ref()?; // Type in the variant tuple, e.g., Vec<u16> or f64
        let inner_type = v.inner_type.as_ref()?; // Inner type, e.g., u16 or f64

        if has_container {
            // When container is used, generate From<FullFieldType> -> EnumName
            Some(quote! {
                impl #impl_generics From<#full_field_type> for #enum_name #ty_generics #where_clause {
                    fn from(value: #full_field_type) -> Self {
                        Self::#variant_ident(value)
                    }
                }
            })
        } else {
            // When no container is used, full_field_type and inner_type are the same
            // So only generate one implementation
            Some(quote! {
                impl #impl_generics From<#inner_type> for #enum_name #ty_generics #where_clause {
                    fn from(value: #inner_type) -> Self {
                        Self::#variant_ident(value)
                    }
                }
            })
        }
    });

    // Generate From impls for unit variants converting from token types
    let unit_from_impls = parsed_variants.iter().filter_map(|v| {
        if !v.is_unit {
            return None;
        }
        let variant_ident = &v.variant_ident;
        let token_ident = &v.token_ident;

        Some(quote! {
            impl #impl_generics From<#tokens_path::#token_ident> for #enum_name #ty_generics #where_clause {
                fn from(_: #tokens_path::#token_ident) -> Self {
                    Self::#variant_ident
                }
            }
        })
    });

    // Check if all variants are unit types
    let all_unit_variants = parsed_variants.iter().all(|v| v.is_unit);

    // Generate from_variant implementation if all variants are unit types
    let from_variant_impl = if all_unit_variants {
        quote! {
            impl #impl_generics #enum_name #ty_generics #where_clause {
                /// Creates a new instance of the enum from a variant token.
                /// The variant token must implement Default.
                pub fn from_variant<V>() -> Self
                where
                    Self: From<V>,
                    V: Default,
                {
                    Self::from(V::default())
                }
            }
        }
    } else {
        quote! {}
    };

    if skip_from_impls {
        quote! {
            #from_variant_impl
            #(#unit_from_impls)*
        }
    } else {
        quote! {
            #(#payload_from_impls)*
            #(#unit_from_impls)*
            #from_variant_impl
        }
    }
}

/// Generates `downcast_ref`, `downcast_mut`, `downcast` methods using the #dtype_variant_path::EnumVariantDowncast trait.
fn generate_downcast_methods(
    dtype_variant_path: &Path,
    enum_name: &Ident,
    generics: &Generics,
    _parsed_variants: &[ParsedVariantInfo],
) -> TokenStream2 {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    quote! {
        impl #impl_generics #enum_name #ty_generics #where_clause {
            /// Attempts to downcast to a shared reference to the target type if the enum holds the
            /// variant corresponding to token type `Token`.
            pub fn downcast_ref<Token>(&self) -> Option<&<Self as #dtype_variant_path::EnumVariantDowncast<Token>>::Target>
            where
                Self: #dtype_variant_path::EnumVariantDowncast<Token>
            {
                <Self as #dtype_variant_path::EnumVariantDowncast<Token>>::downcast_ref(self)
            }

            /// Attempts to downcast to a mutable reference to the target type if the enum holds the
            /// variant corresponding to token type `Token`.
            pub fn downcast_mut<Token>(&mut self) -> Option<&mut <Self as #dtype_variant_path::EnumVariantDowncast<Token>>::Target>
            where
                Self: #dtype_variant_path::EnumVariantDowncast<Token>
            {
                <Self as #dtype_variant_path::EnumVariantDowncast<Token>>::downcast_mut(self)
            }

            /// Attempts to downcast to an owned target type if the enum holds the
            /// variant corresponding to token type `Token`, consuming the enum.
            /// Returns `Some(Target)` on success, or `None` if the enum doesn't hold the expected variant.
            pub fn downcast<Token>(self) -> Option<<Self as #dtype_variant_path::EnumVariantDowncast<Token>>::Target>
            where
                Self: #dtype_variant_path::EnumVariantDowncast<Token>,
                Self: Sized // Required for moving self
            {
                <Self as #dtype_variant_path::EnumVariantDowncast<Token>>::downcast(self)
            }
        }
    }
}

/// Generates a macro for pattern matching on enum variants if `matcher` name is provided.
/// **Uses `generate_match_arm_content`**.
fn generate_matcher_method(
    dtype_variant_path: &Path,
    enum_name: &Ident,
    _generics: &Generics, // Keep signature consistent, used by path closures
    parsed_variants: &[ParsedVariantInfo],
    matcher_ident: &Option<Ident>,
    tokens_path: &Path,
) -> TokenStream2 {
    let matcher_name = match matcher_ident {
        Some(ident) => ident,
        None => return quote! {}, // No matcher name specified
    };

    let all_unit_variants = parsed_variants.iter().all(|v| v.is_unit);
    let internal_matcher_name = format_ident!("_{}", matcher_name);

    // --- Path Generation Closures --- (Captures tokens_path, dtype_variant_path)
    let use_token_path_crate_macro = tokens_path
        .segments
        .first()
        .map(|seg| seg.ident == "crate")
        .unwrap_or(false);
    let use_dtype_variant_path_crate_macro = dtype_variant_path
        .segments
        .first()
        .map(|seg| seg.ident == "crate")
        .unwrap_or(false);

    let tokens_path = if use_token_path_crate_macro {
        let mut rest_path = TokenStream2::new();
        for segment in tokens_path.segments.iter().skip(1) {
            rest_path.extend(quote!( :: #segment));
        }
        quote! { $crate #rest_path }
    } else {
        quote! { #tokens_path }
    };

    let dtype_variant_path = if use_dtype_variant_path_crate_macro {
        quote! { $crate }
    } else {
        quote! { #dtype_variant_path }
    };
    // --- End Path Generation Closures ---

    let generate_macro_rule_arm = generate_macro_rule_arm(
        enum_name,
        parsed_variants,
        tokens_path,
        &dtype_variant_path,
        None,
    );

    // Generate all combinations of macro arms (same logic as before, calling the new generate_macro_arms)
    let macro_rule_arms = if all_unit_variants {
        vec![
            generate_macro_rule_arm(false, false, false, false, false, false),
            generate_macro_rule_arm(false, false, false, true, false, false),
            generate_macro_rule_arm(false, false, false, true, true, false),
            generate_macro_rule_arm(false, false, false, true, false, true),
            generate_macro_rule_arm(false, false, false, true, true, true),
        ]
    } else {
        vec![
            generate_macro_rule_arm(false, false, false, false, false, false),
            generate_macro_rule_arm(false, false, false, true, false, false),
            generate_macro_rule_arm(false, false, false, true, false, true),
            generate_macro_rule_arm(false, false, false, true, true, false),
            generate_macro_rule_arm(false, false, false, true, true, true),
            generate_macro_rule_arm(false, true, false, false, false, false),
            generate_macro_rule_arm(false, true, false, true, false, false),
            generate_macro_rule_arm(false, true, false, true, false, true),
            generate_macro_rule_arm(false, true, false, true, true, false),
            generate_macro_rule_arm(false, true, false, true, true, true),
            generate_macro_rule_arm(false, true, true, false, false, false),
            generate_macro_rule_arm(false, true, true, true, false, false),
            generate_macro_rule_arm(false, true, true, true, false, true),
            generate_macro_rule_arm(false, true, true, true, true, true),
            generate_macro_rule_arm(true, true, false, false, false, false),
            generate_macro_rule_arm(true, true, false, true, false, false),
            generate_macro_rule_arm(true, true, false, true, false, true),
            generate_macro_rule_arm(true, true, false, true, true, false),
            generate_macro_rule_arm(true, true, false, true, true, true),
            generate_macro_rule_arm(true, true, true, false, false, false),
            generate_macro_rule_arm(true, true, true, true, false, false),
            generate_macro_rule_arm(true, true, true, true, false, true),
            generate_macro_rule_arm(true, true, true, true, true, false),
            generate_macro_rule_arm(true, true, true, true, true, true),
        ]
    };

    let macro_arms = macro_rule_arms
        .into_iter()
        .map(
            |MacroRuleArm {
                 pattern_prefix_fragment,
                 pattern_suffix_fragment,
                 variant_bodies,
             }| {
                quote! {
                    ($value:expr, #pattern_prefix_fragment #pattern_suffix_fragment) => {
                        match $value {
                            #variant_bodies
                        }
                    };
                }
            },
        )
        .collect::<Vec<_>>()
        .into_iter()
        .fold(TokenStream2::new(), |mut acc, arm| {
            acc.extend(arm);
            acc
        });

    // --- Final Macro Definition ---
    quote! {
            #[doc(hidden)]
            #[macro_export]
            macro_rules! #internal_matcher_name {
                #macro_arms
            }
            #[allow(unused_imports)]
            pub use #internal_matcher_name as #matcher_name;
    }
}

/// Generates the grouped matcher macro if `grouped_matcher` is specified.
/// **Uses `generate_match_arm_content`**. Does NOT reuse `generate_macro_arms`.
/// Generates the grouped matcher macro if `grouped_matcher` is specified.
/// **Uses `generate_match_arm_content`**. Does NOT reuse `generate_macro_arms`.
fn generate_grouped_matcher_macro(
    dtype_variant_path: &Path,
    enum_name: &Ident,
    _generics: &Generics, // Keep signature consistent
    parsed_variants: &[ParsedVariantInfo],
    parsed_grouped_matcher_opt: &Option<ParsedGroupedMatcher>,
    tokens_path: &Path,
) -> TokenStream2 {
    let Some(parsed_grouped_matcher) = parsed_grouped_matcher_opt else {
        return quote! {}; // No grouped matcher specified
    };

    let macro_name = &parsed_grouped_matcher.macro_name;
    let groups = &parsed_grouped_matcher.groups;
    let internal_macro_name = format_ident!("_{}", macro_name);

    // Build maps for quick lookup: VariantIdent String -> VariantInfo and VariantIdent String -> Group Index
    let mut variant_info_map: IndexMap<String, &ParsedVariantInfo> =
        IndexMap::new();
    let mut variant_to_group_index: IndexMap<String, usize> = IndexMap::new();
    for (group_index, (_, group_variants)) in groups.iter().enumerate() {
        for variant_ident in group_variants {
            variant_to_group_index
                .insert(variant_ident.to_string(), group_index);
        }
    }
    for v in parsed_variants {
        variant_info_map.insert(v.variant_ident.to_string(), v);
    }

    // --- Path Generation Closures --- (Duplicated - consider extracting to a shared place if needed)
    let use_token_path_crate_macro = tokens_path
        .segments
        .first()
        .map(|seg| seg.ident == "crate")
        .unwrap_or(false);
    let use_dtype_variant_path_crate_macro = dtype_variant_path
        .segments
        .first()
        .map(|seg| seg.ident == "crate")
        .unwrap_or(false);

    let tokens_path = if use_token_path_crate_macro {
        let mut rest_path = TokenStream2::new();
        for segment in tokens_path.segments.iter().skip(1) {
            rest_path.extend(quote!( :: #segment));
        }
        quote! { $crate #rest_path }
    } else {
        quote! { #tokens_path }
    };

    let dtype_variant_path = if use_dtype_variant_path_crate_macro {
        quote! { $crate }
    } else {
        quote! { #dtype_variant_path }
    };

    // --- Define the Macro Rule ---
    let create_group_macro_arm = |include_src_ty: bool| {
        // Captures `macro!(value, [V1, V2] (inner) => { body0 }, [V3] => { body1 })`
        let group_pattern_arms = groups
            .iter()
            .enumerate()
            .map(|(group_index, (group_name, group_variants))| {
                let group_variants: Vec<ParsedVariantInfo> = group_variants
                    .iter()
                    .map(|ident| variant_info_map[&ident.to_string()])
                    .cloned()
                    .collect();

                let generate_macro_rule_arm = generate_macro_rule_arm(
                    enum_name,
                    &group_variants,
                    tokens_path.clone(),
                    &dtype_variant_path,
                    Some(group_index as _),
                );

                let all_unit_variants =
                    group_variants.iter().all(|info| info.is_unit);

                // #(#group_variants,)*
                let arm = if all_unit_variants {
                    generate_macro_rule_arm(
                        false, false, false, false, false, false,
                    )
                } else {
                    generate_macro_rule_arm(
                        include_src_ty,
                        true,
                        false,
                        false,
                        false,
                        false,
                    )
                };

                (group_name, arm)
            })
            .collect::<Vec<_>>();

        let group_match_pattern_fragment = {
            let fragments = group_pattern_arms.iter().map(|(name, arm)| {
                let prefix = &arm.pattern_prefix_fragment;
                let suffix = &arm.pattern_suffix_fragment;
                quote! {
                    #name : #prefix #suffix
                }
            });

            quote! {
                #(#fragments,)*
            }
        };

        let all_bodies = {
            let ts = group_pattern_arms
                .iter()
                .map(|(_, arm)| &arm.variant_bodies);

            quote! {
                #(#ts,)*
            }
        };

        quote! {
            // Match the user's grouped input structure
            ( $value:expr, #group_match_pattern_fragment ) => {
                // Expand into the actual Rust match statement
                match $value {
                    #all_bodies // Expand the generated match arms here
                }
            };
        }
    };

    let pat1 = create_group_macro_arm(true);
    let pat2 = create_group_macro_arm(false);

    quote! {
        #[doc(hidden)]
        #[macro_export]
        macro_rules! #internal_macro_name {
            // Match the user's grouped input structure
            #pat1
            #pat2
        }
        #[allow(unused_imports)]
        pub use #internal_macro_name as #macro_name;
    }
}
