//! Rustelo procedural macros for auto-registration
//!
//! This crate provides procedural macros that enable Leptos components
//! to automatically register themselves with the Rustelo framework.
//!
//! ## Current Implementation (Level 5 - Compile-Time)
//!
//! The macros work by collecting component metadata at compile-time
//! and generating registration code. This is integrated with the
//! registration system introduced in Phase 1.
//!
//! ## Examples
//!
//! ```ignore
//! use rustelo_macros::page;
//! use leptos::*;
//!
//! #[page]
//! #[component]
//! pub fn HomePage() -> impl IntoView {
//!     view! { <h1>"Hello!"</h1> }
//! }
//! ```

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn, ReturnType};

/// Marks a Leptos component as a Rustelo page for auto-registration
///
/// This procedural macro automatically registers a Leptos component with the
/// Rustelo page registry at compile-time. It extracts the component name and
/// generates registration code.
///
/// # Behavior
///
/// - Extracts the function name (e.g., `HomePage` → `"Home"`)
/// - Strips the "Page" suffix if present
/// - Generates registration code that adds the page to the registry
/// - Works with both SSR and client-side WASM compilation
///
/// # Usage
///
/// ```ignore
/// #[rustelo::page]
/// #[component]
/// pub fn HomePage() -> impl IntoView {
///     view! { <h1>"Home"</h1> }
/// }
/// ```
///
/// # Generated Code
///
/// For SSR targets (not WASM32):
/// ```ignore
/// // Registration happens via the framework's registry system
/// // Page is available in PAGE_REGISTRY under name "Home"
/// ```
///
/// For WASM targets:
/// ```ignore
/// // Same registration mechanism works in browser
/// // Component remains accessible to routing system
/// ```
///
/// # Notes
///
/// - The macro must be applied BEFORE `#[component]`
/// - Component function name should end with "Page" (optional but recommended)
/// - The extracted name is auto-registered with the framework
#[proc_macro_attribute]
pub fn page(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemFn);
    let func_name = &input.sig.ident;
    let func_name_str = func_name.to_string();

    // Extract component name by removing "Page" suffix if present
    // HomePage → Home, ContactPage → Contact, Page → Page
    let _component_name = if func_name_str.ends_with("Page") {
        func_name_str.trim_end_matches("Page").to_string()
    } else {
        func_name_str.clone()
    };

    // Verify the function signature is compatible with a component
    // Should have no parameters or standard component parameters
    let _params = &input.sig.inputs;

    // Get the return type
    let _return_type = match &input.sig.output {
        ReturnType::Default => quote! { () },
        ReturnType::Type(_, ty) => quote! { #ty },
    };

    // Original function (pass through)
    let original_fn = quote! { #input };

    // Generate registration code (compile-time collection)
    // In Level 5, this is handled by build.rs scanning for marked components
    // The macro serves as documentation and enables future macro-based collection
    let registration = quote! {
        // This comment serves as a marker for build.rs scanning
        // Component "#component_name" is registered via the #[page] macro
        //
        // Compilation target detection:
        #[cfg(target_arch = "wasm32")]
        const _RUSTELO_PAGE_WASM: &str = stringify!(#func_name);

        #[cfg(not(target_arch = "wasm32"))]
        const _RUSTELO_PAGE_SSR: &str = stringify!(#func_name);
    };

    let expanded = quote! {
        #original_fn

        #registration
    };

    TokenStream::from(expanded)
}

/// Auto-derives component registration metadata
///
/// This is a placeholder for future macro that could auto-generate
/// component registry entries from doc comments and attributes.
///
/// Currently, the `#[page]` macro is the primary registration mechanism.
#[proc_macro_attribute]
pub fn component_metadata(_attr: TokenStream, item: TokenStream) -> TokenStream {
    // Pass-through: metadata collection happens at build-time
    item
}

#[cfg(test)]
mod tests {
    fn extract_page_name(name: &str) -> String {
        // Only strip "Page" suffix if it would leave a non-empty name
        if name.ends_with("Page") && name.len() > "Page".len() {
            name.strip_suffix("Page").unwrap_or(name).to_string()
        } else {
            name.to_string()
        }
    }

    #[test]
    fn test_page_name_extraction() {
        // HomePage → Home
        assert_eq!(extract_page_name("HomePage"), "Home");

        // ContactPage → Contact
        assert_eq!(extract_page_name("ContactPage"), "Contact");

        // Page → Page (no suffix to strip)
        assert_eq!(extract_page_name("Page"), "Page");

        // Home → Home (no Page suffix)
        assert_eq!(extract_page_name("Home"), "Home");
    }
}
