//! Contact form component
//!
//! This component provides a user-friendly contact form with validation,
//! error handling, and success feedback using Leptos reactive primitives.

use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use wasm_bindgen::JsCast;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_futures::spawn_local;

#[cfg(not(target_arch = "wasm32"))]
fn spawn_local<F>(_fut: F)
where
    F: std::future::Future<Output = ()> + 'static,
{
    // On server side, don't execute async operations that require browser APIs
}
use web_sys::{Event, HtmlInputElement, HtmlTextAreaElement};

/// Safely extract value from input element
fn extract_input_value(event: &Event) -> Option<String> {
    event
        .target()
        .and_then(|t| t.dyn_into::<HtmlInputElement>().ok())
        .map(|input| input.value())
}

/// Safely extract value from textarea element
fn extract_textarea_value(event: &Event) -> Option<String> {
    event
        .target()
        .and_then(|t| t.dyn_into::<HtmlTextAreaElement>().ok())
        .map(|textarea| textarea.value())
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContactFormData {
    pub name: String,
    pub email: String,
    pub subject: String,
    pub message: String,
    pub recipient: Option<String>,
}

impl Default for ContactFormData {
    fn default() -> Self {
        Self {
            name: String::new(),
            email: String::new(),
            subject: String::new(),
            message: String::new(),
            recipient: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContactFormResponse {
    pub message: String,
    pub message_id: String,
    pub status: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContactFormError {
    pub error: String,
    pub message: String,
    pub code: String,
}

#[derive(Debug, Clone)]
pub enum FormState {
    Idle,
    Submitting,
    Success(ContactFormResponse),
    Error(String),
}

#[component]
pub fn ContactForm(
    /// Optional recipient email address
    #[prop(optional)]
    recipient: Option<String>,
    /// Form title
    #[prop(optional)]
    title: Option<String>,
    /// Form description
    #[prop(optional)]
    description: Option<String>,
    /// Custom CSS class
    #[prop(optional)]
    class: Option<String>,
    /// Show success message after submission
    #[prop(default = true)]
    show_success: bool,
    /// Reset form after successful submission
    #[prop(default = true)]
    reset_after_success: bool,
    /// Custom submit button text
    #[prop(optional)]
    submit_text: Option<String>,
) -> impl IntoView {
    let (form_data, set_form_data) = signal(ContactFormData::default());
    let (form_state, set_form_state) = signal(FormState::Idle);
    let (validation_errors, set_validation_errors) = signal(HashMap::<String, String>::new());

    // Set recipient if provided
    if let Some(recipient_email) = recipient {
        set_form_data.update(|data| data.recipient = Some(recipient_email));
    }

    // Validation functions
    let validate_email =
        |email: &str| -> bool { email.contains('@') && email.len() > 5 && email.len() < 255 };

    let validate_required = |value: &str| -> bool { !value.trim().is_empty() };

    let validate_length = |value: &str, max: usize| -> bool { value.len() <= max };

    // Input handlers
    let on_name_input = move |ev: Event| {
        if let Some(value) = extract_input_value(&ev) {
            set_form_data.update(|data| data.name = value);

            // Clear validation error when user starts typing
            set_validation_errors.update(|errors| {
                errors.remove("name");
            });
        }
    };

    let on_email_input = move |ev: Event| {
        if let Some(value) = extract_input_value(&ev) {
            set_form_data.update(|data| data.email = value);

            // Clear validation error when user starts typing
            set_validation_errors.update(|errors| {
                errors.remove("email");
            });
        }
    };

    let on_subject_input = move |ev: Event| {
        if let Some(value) = extract_input_value(&ev) {
            set_form_data.update(|data| data.subject = value);

            // Clear validation error when user starts typing
            set_validation_errors.update(|errors| {
                errors.remove("subject");
            });
        }
    };

    let on_message_input = move |ev: Event| {
        if let Some(value) = extract_textarea_value(&ev) {
            set_form_data.update(|data| data.message = value);

            // Clear validation error when user starts typing
            set_validation_errors.update(|errors| {
                errors.remove("message");
            });
        }
    };

    // Form validation
    let validate_form = move |data: &ContactFormData| -> HashMap<String, String> {
        let mut errors = HashMap::new();

        if !validate_required(&data.name) {
            errors.insert("name".to_string(), "Name is required".to_string());
        } else if !validate_length(&data.name, 100) {
            errors.insert(
                "name".to_string(),
                "Name must be less than 100 characters".to_string(),
            );
        }

        if !validate_required(&data.email) {
            errors.insert("email".to_string(), "Email is required".to_string());
        } else if !validate_email(&data.email) {
            errors.insert(
                "email".to_string(),
                "Please enter a valid email address".to_string(),
            );
        }

        if !validate_required(&data.subject) {
            errors.insert("subject".to_string(), "Subject is required".to_string());
        } else if !validate_length(&data.subject, 200) {
            errors.insert(
                "subject".to_string(),
                "Subject must be less than 200 characters".to_string(),
            );
        }

        if !validate_required(&data.message) {
            errors.insert("message".to_string(), "Message is required".to_string());
        } else if !validate_length(&data.message, 5000) {
            errors.insert(
                "message".to_string(),
                "Message must be less than 5000 characters".to_string(),
            );
        }

        errors
    };

    // Form submission
    let on_submit = move |ev: leptos::ev::SubmitEvent| {
        ev.prevent_default();

        let data = form_data.get();
        let errors = validate_form(&data);

        if !errors.is_empty() {
            set_validation_errors.set(errors);
            return;
        }

        // Clear validation errors
        set_validation_errors.set(HashMap::new());
        set_form_state.set(FormState::Submitting);

        // Submit the form
        spawn_local(async move {
            let body = match serde_json::to_string(&data) {
                Ok(json) => json,
                Err(_) => {
                    set_form_state.set(FormState::Error(
                        "Failed to serialize form data".to_string(),
                    ));
                    return;
                }
            };

            let client = reqwasm::http::Request::post("/api/email/contact")
                .header("Content-Type", "application/json")
                .body(body);
            let response = client.send().await;

            match response {
                Ok(resp) => {
                    if resp.status() == 200 {
                        match resp.json::<ContactFormResponse>().await {
                            Ok(success_response) => {
                                set_form_state.set(FormState::Success(success_response));

                                if reset_after_success {
                                    set_form_data.set(ContactFormData::default());
                                }
                            }
                            Err(e) => {
                                set_form_state.set(FormState::Error(format!(
                                    "Failed to parse response: {}",
                                    e
                                )));
                            }
                        }
                    } else {
                        match resp.json::<ContactFormError>().await {
                            Ok(error_response) => {
                                set_form_state.set(FormState::Error(error_response.message));
                            }
                            Err(_) => {
                                set_form_state.set(FormState::Error(format!(
                                    "Server error: {}",
                                    resp.status()
                                )));
                            }
                        }
                    }
                }
                Err(e) => {
                    set_form_state.set(FormState::Error(format!("Network error: {}", e)));
                }
            }
        });
    };

    // Helper to get field error
    let get_field_error = move |field: &'static str| -> Option<String> {
        validation_errors.get().get(field).cloned()
    };

    // Helper to check if field has error
    let has_field_error =
        move |field: &'static str| -> bool { validation_errors.get().contains_key(field) };

    view! {
        <div class={format!("contact-form {}", class.unwrap_or_default())}>
            {title.map(|t| view! {
                <div class="form-header mb-6">
                    <h2 class="text-2xl font-bold text-gray-900 mb-2">{t}</h2>
                    {description.map(|d| view! {
                        <p class="text-gray-600">{d}</p>
                    })}
                </div>
            })}

            <form on:submit=on_submit class="space-y-6">
                // Name field
                <div class="form-group">
                    <label
                        for="contact-name"
                        class="block text-sm font-medium text-gray-700 mb-2"
                    >
                        "Name"
                        <span class="text-red-500 ml-1">*</span>
                    </label>
                    <input
                        type="text"
                        id="contact-name"
                        name="name"
                        value={move || form_data.get().name}
                        on:input=on_name_input
                        class={move || format!(
                            "w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {}",
                            if has_field_error("name") { "border-red-500" } else { "border-gray-300" }
                        )}
                        placeholder="Your full name"
                        required
                    />
                    {move || get_field_error("name").map(|error| view! {
                        <p class="mt-1 text-sm text-red-600">{error}</p>
                    })}
                </div>

                // Email field
                <div class="form-group">
                    <label
                        for="contact-email"
                        class="block text-sm font-medium text-gray-700 mb-2"
                    >
                        "Email"
                        <span class="text-red-500 ml-1">*</span>
                    </label>
                    <input
                        type="email"
                        id="contact-email"
                        name="email"
                        value={move || form_data.get().email}
                        on:input=on_email_input
                        class={move || format!(
                            "w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {}",
                            if has_field_error("email") { "border-red-500" } else { "border-gray-300" }
                        )}
                        placeholder="your.email@example.com"
                        required
                    />
                    {move || get_field_error("email").map(|error| view! {
                        <p class="mt-1 text-sm text-red-600">{error}</p>
                    })}
                </div>

                // Subject field
                <div class="form-group">
                    <label
                        for="contact-subject"
                        class="block text-sm font-medium text-gray-700 mb-2"
                    >
                        "Subject"
                        <span class="text-red-500 ml-1">*</span>
                    </label>
                    <input
                        type="text"
                        id="contact-subject"
                        name="subject"
                        value={move || form_data.get().subject}
                        on:input=on_subject_input
                        class={move || format!(
                            "w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {}",
                            if has_field_error("subject") { "border-red-500" } else { "border-gray-300" }
                        )}
                        placeholder="What is this about?"
                        required
                    />
                    {move || get_field_error("subject").map(|error| view! {
                        <p class="mt-1 text-sm text-red-600">{error}</p>
                    })}
                </div>

                // Message field
                <div class="form-group">
                    <label
                        for="contact-message"
                        class="block text-sm font-medium text-gray-700 mb-2"
                    >
                        "Message"
                        <span class="text-red-500 ml-1">*</span>
                    </label>
                    <textarea
                        id="contact-message"
                        name="message"
                        rows="6"
                        prop:value={move || form_data.get().message}
                        on:input=on_message_input
                        class={move || format!(
                            "w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 {}",
                            if has_field_error("message") { "border-red-500" } else { "border-gray-300" }
                        )}
                        placeholder="Please describe your message in detail..."
                        required
                    />
                    {move || get_field_error("message").map(|error| view! {
                        <p class="mt-1 text-sm text-red-600">{error}</p>
                    })}
                </div>

                // Submit button
                <div class="form-group">
                    <button
                        type="submit"
                        disabled={move || matches!(form_state.get(), FormState::Submitting)}
                        class={move || format!(
                            "w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 {}",
                            if matches!(form_state.get(), FormState::Submitting) {
                                "bg-gray-400 cursor-not-allowed"
                            } else {
                                "bg-blue-600 hover:bg-blue-700"
                            }
                        )}
                    >
                        {move || match form_state.get() {
                            FormState::Submitting => "Sending...".to_string(),
                            _ => submit_text.clone().unwrap_or_else(|| "Send Message".to_string()),
                        }}
                    </button>
                </div>

                // Status messages
                {move || match form_state.get() {
                    FormState::Success(response) if show_success => Some(view! {
                        <div class="mt-4 p-4 bg-green-50 border border-green-200 rounded-md">
                            <div class="flex">
                                <div class="flex-shrink-0">
                                    <svg class="h-5 w-5 text-green-400" fill="currentColor" viewBox="0 0 20 20">
                                        <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
                                    </svg>
                                </div>
                                <div class="ml-3">
                                    <p class="text-sm font-medium text-green-800">
                                        "Message sent successfully!"
                                    </p>
                                    <p class="mt-1 text-sm text-green-700">
                                        {response.message}
                                    </p>
                                </div>
                            </div>
                        </div>
                    }),
                    FormState::Error(error) => Some(view! {
                        <div class="mt-4 p-4 bg-red-50 border border-red-200 rounded-md">
                            <div class="flex">
                                <div class="flex-shrink-0">
                                    <svg class="h-5 w-5 text-red-400" fill="currentColor" viewBox="0 0 20 20">
                                        <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
                                    </svg>
                                </div>
                                <div class="ml-3">
                                    <p class="text-sm font-medium text-red-800">
                                        "Failed to send message"
                                    </p>
                                    <p class="mt-1 text-sm text-red-700">
                                        {error}
                                    </p>
                                </div>
                            </div>
                        </div>
                    }),
                    _ => None,
                }}
            </form>
        </div>
    }
}
