/// Example showing how to extend Rustelo's configuration-driven architecture
/// with custom code when TOML configuration can't express your needs.
/// 
/// This follows the 90/10 rule:
/// - 90%: Standard pages from TOML configuration → Generated automatically
/// - 10%: Custom components → Generated in build.rs when needed
/// 
/// This example shows the build.rs patterns for the 10% case.

use std::env;
use std::fs;
use std::path::Path;

/// Main function showing how to extend the foundation build system
/// This would typically be in your project's build.rs file
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("🔧 Rustelo Extension Pattern Example");
    println!("====================================");
    println!();
    println!("This example shows how to extend foundation-generated code");
    println!("with custom components when configuration isn't sufficient.");
    println!();

    // Step 1: Generate foundation components from TOML (90%)
    generate_foundation_components()?;
    
    // Step 2: Generate custom components for complex needs (10%)
    generate_custom_extensions()?;
    
    // Step 3: Create integration code
    generate_integration_code()?;

    println!("✅ Extension generation complete!");
    println!("💡 Your app now has both configured and custom components");
    Ok(())
}

/// Step 1: Generate standard foundation components from TOML configuration
/// This handles 90% of typical use cases
fn generate_foundation_components() -> Result<(), Box<dyn std::error::Error>> {
    println!("📋 Step 1: Foundation Component Generation (90%)");
    println!("================================================");
    
    // This is what rustelo_core_lib::build::generate_shared_resources() does
    println!("🏗️  Generating from TOML configuration:");
    println!("   • site/config/routes/*.toml → RouteComponent enum + page components");
    println!("   • content/content-kinds.toml → Content type handlers");
    println!("   • content/locales/* → i18n setup and language discovery");
    println!("   • config/design-system.toml → Theme and styling configuration");
    
    // In real build.rs, you would call:
    // rustelo_core_lib::build::generate_shared_resources()?;
    
    // For demo, show what gets generated
    demo_show_generated_foundation_code()?;
    
    println!("✅ Foundation components generated from configuration");
    Ok(())
}

/// Step 2: Generate custom components for complex business logic (10%)
/// Only when TOML configuration can't express your needs
fn generate_custom_extensions() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n🛠️  Step 2: Custom Extension Generation (10%)");
    println!("=============================================");
    
    println!("⚠️  Custom code needed for:");
    println!("   • Complex interactive dashboard with real-time data");
    println!("   • Third-party payment integration with Stripe");
    println!("   • Advanced data visualization components");
    println!("   • Custom authentication flows");
    
    // Generate custom dashboard component
    generate_custom_dashboard()?;
    
    // Generate payment integration component  
    generate_payment_integration()?;
    
    // Generate data visualization component
    generate_data_visualization()?;
    
    println!("✅ Custom extensions generated for complex requirements");
    Ok(())
}

/// Generate a custom dashboard component with complex state management
fn generate_custom_dashboard() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n   🎛️  Generating CustomDashboard component...");
    
    let dashboard_component = r#"
//! Custom Dashboard Component - Generated in build.rs
//! This handles complex real-time data that can't be configured in TOML

use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use wasm_bindgen_futures::spawn_local;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashboardMetrics {
    pub active_users: u32,
    pub revenue: f64,
    pub conversions: u32,
    pub page_views: u32,
}

/// Custom Dashboard with real-time updates and complex interactions
/// This can't be expressed in TOML config due to complex state management
#[component]
pub fn CustomDashboard() -> impl IntoView {
    // Complex reactive state that requires custom logic
    let (metrics, set_metrics) = create_signal(DashboardMetrics {
        active_users: 0,
        revenue: 0.0,
        conversions: 0,
        page_views: 0,
    });
    
    let (is_loading, set_loading) = create_signal(true);
    let (error_message, set_error) = create_signal(Option::<String>::None);
    
    // Real-time data fetching with error handling
    create_effect(move |_| {
        spawn_local(async move {
            set_loading.set(true);
            set_error.set(None);
            
            match fetch_realtime_metrics().await {
                Ok(new_metrics) => {
                    set_metrics.set(new_metrics);
                    set_loading.set(false);
                }
                Err(e) => {
                    set_error.set(Some(e.to_string()));
                    set_loading.set(false);
                }
            }
        });
    });
    
    // Auto-refresh every 30 seconds
    create_effect(move |_| {
        let interval = web_sys::window()
            .unwrap()
            .set_interval_with_callback_and_timeout_and_arguments_0(
                &wasm_bindgen::closure::Closure::wrap(Box::new(move || {
                    spawn_local(async move {
                        if let Ok(new_metrics) = fetch_realtime_metrics().await {
                            set_metrics.set(new_metrics);
                        }
                    });
                }) as Box<dyn FnMut()>)
                .into_js_value()
                .unchecked_ref(),
                30000, // 30 seconds
            );
    });

    view! {
        <div class="custom-dashboard">
            <div class="dashboard-header">
                <h1>"Real-Time Dashboard"</h1>
                {move || {
                    if is_loading.get() {
                        view! { <div class="loading-spinner">"Loading metrics..."</div> }
                    } else {
                        view! { <div class="last-updated">"Live data"</div> }
                    }
                }}
            </div>
            
            {move || {
                if let Some(error) = error_message.get() {
                    view! {
                        <div class="error-message">
                            "Error loading metrics: " {error}
                        </div>
                    }
                } else {
                    let current_metrics = metrics.get();
                    view! {
                        <div class="metrics-grid">
                            <MetricCard 
                                title="Active Users"
                                value=current_metrics.active_users.to_string()
                                icon="👥"
                            />
                            <MetricCard 
                                title="Revenue"
                                value=format!("${:.2}", current_metrics.revenue)
                                icon="💰"
                            />
                            <MetricCard 
                                title="Conversions"
                                value=current_metrics.conversions.to_string()
                                icon="🎯"
                            />
                            <MetricCard 
                                title="Page Views"
                                value=current_metrics.page_views.to_string()
                                icon="👁️"
                            />
                        </div>
                    }
                }
            }}
            
            <div class="dashboard-charts">
                <RealtimeChart data=metrics />
                <ConversionFunnel data=metrics />
            </div>
        </div>
    }
}

#[component]
fn MetricCard(
    title: String,
    value: String, 
    icon: String,
) -> impl IntoView {
    view! {
        <div class="metric-card">
            <div class="metric-icon">{icon}</div>
            <div class="metric-content">
                <h3>{title}</h3>
                <div class="metric-value">{value}</div>
            </div>
        </div>
    }
}

// Mock function - in real app this would call your analytics API
async fn fetch_realtime_metrics() -> Result<DashboardMetrics, Box<dyn std::error::Error>> {
    // Simulate API call delay
    gloo_timers::future::TimeoutFuture::new(100).await;
    
    Ok(DashboardMetrics {
        active_users: 1247,
        revenue: 52_340.75,
        conversions: 89,
        page_views: 15_692,
    })
}

// These would be other custom components
#[component] 
fn RealtimeChart(data: ReadSignal<DashboardMetrics>) -> impl IntoView {
    view! { <div class="realtime-chart">"Chart placeholder"</div> }
}

#[component]
fn ConversionFunnel(data: ReadSignal<DashboardMetrics>) -> impl IntoView {
    view! { <div class="conversion-funnel">"Funnel placeholder"</div> }
}
"#;
    
    // In real build.rs, write to OUT_DIR
    let out_dir = env::var("OUT_DIR").unwrap_or("target/debug".to_string());
    let dashboard_path = Path::new(&out_dir).join("custom_dashboard.rs");
    fs::write(dashboard_path, dashboard_component)?;
    
    println!("      ✅ CustomDashboard component generated");
    Ok(())
}

/// Generate payment integration component with Stripe
fn generate_payment_integration() -> Result<(), Box<dyn std::error::Error>> {
    println!("   💳 Generating PaymentIntegration component...");
    
    let payment_component = r#"
//! Custom Payment Integration - Generated in build.rs
//! Handles Stripe payment flow that can't be configured in TOML

use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaymentRequest {
    pub amount: u32,
    pub currency: String,
    pub description: String,
}

/// Custom Payment Component with Stripe integration
/// This requires custom logic that can't be expressed in TOML configuration
#[component]
pub fn StripePaymentForm(
    amount: u32,
    description: String,
    on_success: Callback<String>, // payment_intent_id
    on_error: Callback<String>,
) -> impl IntoView {
    let (is_processing, set_processing) = create_signal(false);
    let (stripe_elements, set_stripe_elements) = create_signal(Option::<web_sys::Element>::None);
    
    // Initialize Stripe Elements on mount
    create_effect(move |_| {
        spawn_local(async move {
            match initialize_stripe_elements().await {
                Ok(elements) => set_stripe_elements.set(Some(elements)),
                Err(e) => on_error.call(format!("Failed to initialize Stripe: {}", e)),
            }
        });
    });
    
    let handle_submit = move |_| {
        set_processing.set(true);
        
        let payment_request = PaymentRequest {
            amount,
            currency: "usd".to_string(),
            description: description.clone(),
        };
        
        spawn_local(async move {
            match process_stripe_payment(payment_request).await {
                Ok(payment_intent_id) => {
                    set_processing.set(false);
                    on_success.call(payment_intent_id);
                }
                Err(e) => {
                    set_processing.set(false);
                    on_error.call(e.to_string());
                }
            }
        });
    };

    view! {
        <div class="stripe-payment-form">
            <div class="payment-details">
                <h3>"Complete your payment"</h3>
                <div class="amount">
                    {format!("${:.2}", amount as f64 / 100.0)}
                </div>
                <div class="description">{description}</div>
            </div>
            
            <div class="stripe-elements-container">
                // Stripe Elements would mount here
                <div id="card-element"></div>
            </div>
            
            <button 
                class="pay-button"
                disabled=move || is_processing.get()
                on:click=handle_submit
            >
                {move || {
                    if is_processing.get() {
                        "Processing..."
                    } else {
                        "Pay Now"
                    }
                }}
            </button>
        </div>
    }
}

// Mock Stripe integration functions - in real app these would call Stripe API
async fn initialize_stripe_elements() -> Result<web_sys::Element, Box<dyn std::error::Error>> {
    // Mock implementation
    gloo_timers::future::TimeoutFuture::new(500).await;
    Ok(web_sys::window().unwrap().document().unwrap().create_element("div")?)
}

async fn process_stripe_payment(request: PaymentRequest) -> Result<String, Box<dyn std::error::Error>> {
    // Mock payment processing
    gloo_timers::future::TimeoutFuture::new(2000).await;
    Ok("pi_1234567890".to_string())
}
"#;
    
    let out_dir = env::var("OUT_DIR").unwrap_or("target/debug".to_string());
    let payment_path = Path::new(&out_dir).join("payment_integration.rs");
    fs::write(payment_path, payment_component)?;
    
    println!("      ✅ StripePaymentForm component generated");
    Ok(())
}

/// Generate data visualization component
fn generate_data_visualization() -> Result<(), Box<dyn std::error::Error>> {
    println!("   📊 Generating DataVisualization component...");
    
    let viz_component = r#"
//! Custom Data Visualization - Generated in build.rs  
//! Advanced charts that can't be configured in TOML

use leptos::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChartDataPoint {
    pub x: f64,
    pub y: f64,
    pub label: String,
}

/// Custom Interactive Chart Component
/// Requires complex D3.js integration that can't be expressed in TOML
#[component]
pub fn InteractiveChart(
    data: ReadSignal<Vec<ChartDataPoint>>,
    chart_type: String,
    width: u32,
    height: u32,
) -> impl IntoView {
    let canvas_ref = create_node_ref::<web_sys::HtmlCanvasElement>();
    
    // Re-render chart when data changes
    create_effect(move |_| {
        let current_data = data.get();
        
        if let Some(canvas) = canvas_ref.get() {
            spawn_local(async move {
                render_chart_to_canvas(canvas, current_data, &chart_type).await;
            });
        }
    });

    view! {
        <div class="interactive-chart-container">
            <canvas
                node_ref=canvas_ref
                width=width
                height=height
                class="chart-canvas"
            ></canvas>
            <div class="chart-controls">
                <ChartLegend data=data />
                <ChartTooltip />
            </div>
        </div>
    }
}

#[component]
fn ChartLegend(data: ReadSignal<Vec<ChartDataPoint>>) -> impl IntoView {
    view! {
        <div class="chart-legend">
            <For
                each=move || data.get()
                key=|point| point.label.clone()
                children=move |point| {
                    view! {
                        <div class="legend-item">
                            <span class="legend-color"></span>
                            <span class="legend-label">{point.label}</span>
                        </div>
                    }
                }
            />
        </div>
    }
}

#[component]
fn ChartTooltip() -> impl IntoView {
    view! {
        <div class="chart-tooltip" style="display: none;">
            <div class="tooltip-content"></div>
        </div>
    }
}
"#;

// Mock chart rendering - in real app this would use D3.js or Canvas API  
async fn render_chart_to_canvas(
    _canvas: web_sys::HtmlCanvasElement, 
    _data: Vec<ChartDataPoint>,
    _chart_type: &str,
) {
    // Mock implementation for example
}
    
    let out_dir = env::var("OUT_DIR").unwrap_or("target/debug".to_string());
    let viz_path = Path::new(&out_dir).join("data_visualization.rs");
    fs::write(viz_path, viz_component)?;
    
    println!("      ✅ InteractiveChart component generated");
    Ok(())
}

/// Step 3: Generate integration code that combines foundation + custom components
fn generate_integration_code() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n🔗 Step 3: Integration Code Generation");
    println!("=====================================");
    
    println!("🔧 Generating integration module...");
    
    let integration_code = r#"
//! Integration module - Generated in build.rs
//! Combines foundation-generated components with custom extensions

// Include all foundation-generated components
include!(concat!(env!("OUT_DIR"), "/generated_routes.rs"));
include!(concat!(env!("OUT_DIR"), "/generated_components.rs"));
include!(concat!(env!("OUT_DIR"), "/content_kinds_generated.rs"));

// Include all custom-generated components  
include!(concat!(env!("OUT_DIR"), "/custom_dashboard.rs"));
include!(concat!(env!("OUT_DIR"), "/payment_integration.rs"));
include!(concat!(env!("OUT_DIR"), "/data_visualization.rs"));

use leptos::prelude::*;

/// Main app component that combines foundation and custom components
#[component]
pub fn ExtendedApp() -> impl IntoView {
    view! {
        // Foundation-generated providers and routing
        <AppStateProvider>
            <LanguageProvider>
                <ThemeProvider>
                    <Router>
                        <Routes>
                            // Foundation-generated routes (90%)
                            <Route path="/" view=GeneratedHomePage />
                            <Route path="/about" view=GeneratedAboutPage />
                            <Route path="/services" view=GeneratedServicesPage />
                            
                            // Custom routes for complex functionality (10%)
                            <Route path="/dashboard" view=CustomDashboard />
                            <Route path="/payment" view=PaymentPage />
                            <Route path="/analytics" view=AnalyticsPage />
                        </Routes>
                    </Router>
                </ThemeProvider>
            </LanguageProvider>
        </AppStateProvider>
    }
}

/// Custom payment page that uses both foundation and custom components
#[component]
fn PaymentPage() -> impl IntoView {
    let (payment_success, set_payment_success) = create_signal(false);
    let (error_message, set_error_message) = create_signal(Option::<String>::None);
    
    let on_payment_success = Callback::new(move |payment_id: String| {
        logging::log!("Payment successful: {}", payment_id);
        set_payment_success.set(true);
    });
    
    let on_payment_error = Callback::new(move |error: String| {
        logging::error!("Payment failed: {}", error);
        set_error_message.set(Some(error));
    });

    view! {
        // Foundation-generated page wrapper
        <GeneratedPageWrapper title_key="payment-title">
            
            {move || {
                if payment_success.get() {
                    view! {
                        <div class="payment-success">
                            <h2>"Payment Successful!"</h2>
                            <p>"Thank you for your purchase."</p>
                        </div>
                    }
                } else {
                    view! {
                        <div class="payment-form">
                            // Custom Stripe integration component
                            <StripePaymentForm
                                amount=2999  // $29.99
                                description="Premium Plan".to_string()
                                on_success=on_payment_success
                                on_error=on_payment_error
                            />
                            
                            {move || {
                                if let Some(error) = error_message.get() {
                                    view! {
                                        <div class="error-message">
                                            "Error: " {error}
                                        </div>
                                    }
                                } else {
                                    view! { <div></div> }
                                }
                            }}
                        </div>
                    }
                }
            }}
            
        </GeneratedPageWrapper>
    }
}

/// Analytics page combining foundation layout with custom visualization
#[component] 
fn AnalyticsPage() -> impl IntoView {
    // Mock chart data
    let chart_data = create_signal(vec![
        ChartDataPoint { x: 0.0, y: 10.0, label: "Jan".to_string() },
        ChartDataPoint { x: 1.0, y: 15.0, label: "Feb".to_string() },
        ChartDataPoint { x: 2.0, y: 8.0, label: "Mar".to_string() },
        ChartDataPoint { x: 3.0, y: 22.0, label: "Apr".to_string() },
    ]);

    view! {
        // Foundation-generated page wrapper
        <GeneratedPageWrapper title_key="analytics-title">
            <div class="analytics-page">
                // Foundation-generated page header
                <GeneratedPageHeader />
                
                <div class="analytics-content">
                    // Custom dashboard component
                    <CustomDashboard />
                    
                    // Custom chart component  
                    <InteractiveChart
                        data=chart_data.0
                        chart_type="bar".to_string()
                        width=800
                        height=400
                    />
                </div>
            </div>
        </GeneratedPageWrapper>
    }
}
"#;
    
    let out_dir = env::var("OUT_DIR").unwrap_or("target/debug".to_string());
    let integration_path = Path::new(&out_dir).join("extended_app.rs");
    fs::write(integration_path, integration_code)?;
    
    println!("   ✅ Integration code generated");
    println!("\n💡 Your app.rs can now include:");
    println!("   include!(concat!(env!(\"OUT_DIR\"), \"/extended_app.rs\"));");
    println!("   ");
    println!("   fn main() {{");
    println!("       leptos::mount_to_body(|| view! {{ <ExtendedApp /> }});");
    println!("   }}");
    
    Ok(())
}

/// Demo function showing what foundation generates automatically
fn demo_show_generated_foundation_code() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n   📄 Example generated foundation code:");
    println!("   ");
    println!("   // Generated from site/config/routes/en.toml");
    println!("   #[derive(Debug, Clone, PartialEq, Eq)]");
    println!("   pub enum RouteComponent {{");
    println!("       Home,    // from [[routes]] component = \"Home\"");
    println!("       About,   // from [[routes]] component = \"About\"");
    println!("       Services,// from [[routes]] component = \"Services\"");
    println!("   }}");
    println!("   ");
    println!("   // Generated page component from TOML config");
    println!("   #[component]");
    println!("   pub fn GeneratedAboutPage() -> impl IntoView {{");
    println!("       let title = t(\"about-title\");  // from title_key in TOML");
    println!("       view! {{");
    println!("           <div class=\"page-container about-page\">");
    println!("               <PageHeader title=title />");
    println!("           </div>");
    println!("       }}");
    println!("   }}");
    
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_extension_generation() {
        // Test that extension generation functions work without panicking
        let result = generate_foundation_components();
        assert!(result.is_ok(), "Foundation generation should succeed");
        
        let result = generate_custom_extensions();
        assert!(result.is_ok(), "Custom extension generation should succeed");
        
        let result = generate_integration_code();
        assert!(result.is_ok(), "Integration code generation should succeed");
    }
}