//! Registration modal component for guest-to-user conversion.

use leptos::prelude::*;

use super::forms::{ErrorAlert, SubmitButton, TextInput};
use crate::utils::use_escape_key;

/// Response from the register-guest API endpoint.
#[derive(Clone, serde::Deserialize)]
pub struct RegisterGuestResponse {
    pub success: bool,
    pub username: String,
}

/// Registration modal for converting a guest account to a full user account.
///
/// Props:
/// - `open`: Signal controlling modal visibility
/// - `on_close`: Callback when modal should close
/// - `on_success`: Callback when registration succeeds (receives new username)
#[component]
pub fn RegisterModal(
    #[prop(into)] open: Signal<bool>,
    on_close: Callback<()>,
    #[prop(optional)] on_success: Option<Callback<String>>,
) -> impl IntoView {
    let (username, set_username) = signal(String::new());
    let (email, set_email) = signal(String::new());
    let (password, set_password) = signal(String::new());
    let (confirm_password, set_confirm_password) = signal(String::new());
    let (error, set_error) = signal(Option::<String>::None);
    let (pending, set_pending) = signal(false);

    // Handle escape key
    use_escape_key(open, on_close.clone());

    let on_close_backdrop = on_close.clone();
    let on_close_button = on_close.clone();

    // Client-side validation
    let validate = move || -> Result<(), String> {
        let username_val = username.get();
        let password_val = password.get();
        let confirm_val = confirm_password.get();
        let email_val = email.get();

        // Username validation: 3-30 chars, alphanumeric + underscore
        if username_val.len() < 3 || username_val.len() > 30 {
            return Err("Username must be between 3 and 30 characters".to_string());
        }
        if !username_val
            .chars()
            .all(|c| c.is_alphanumeric() || c == '_')
        {
            return Err("Username can only contain letters, numbers, and underscores".to_string());
        }

        // Password validation: 8+ chars
        if password_val.len() < 8 {
            return Err("Password must be at least 8 characters".to_string());
        }

        // Confirm password
        if password_val != confirm_val {
            return Err("Passwords do not match".to_string());
        }

        // Email validation (optional, but must be valid if provided)
        if !email_val.is_empty() && !email_val.contains('@') {
            return Err("Please enter a valid email address".to_string());
        }

        Ok(())
    };

    // Submit handler
    #[cfg(feature = "hydrate")]
    let on_submit = {
        let on_close = on_close.clone();
        move |ev: leptos::ev::SubmitEvent| {
            ev.prevent_default();

            // Validate first
            if let Err(msg) = validate() {
                set_error.set(Some(msg));
                return;
            }

            set_error.set(None);
            set_pending.set(true);

            let username_val = username.get();
            let email_val = email.get();
            let password_val = password.get();
            let confirm_val = confirm_password.get();

            let on_close = on_close.clone();
            let on_success = on_success.clone();

            leptos::task::spawn_local(async move {
                use gloo_net::http::Request;

                let request_body = serde_json::json!({
                    "username": username_val,
                    "email": if email_val.is_empty() { None } else { Some(email_val) },
                    "password": password_val,
                    "confirm_password": confirm_val,
                });

                let result = Request::post("/api/auth/register-guest")
                    .header("Content-Type", "application/json")
                    .body(request_body.to_string())
                    .unwrap()
                    .send()
                    .await;

                set_pending.set(false);

                match result {
                    Ok(resp) => {
                        if resp.ok() {
                            if let Ok(data) = resp.json::<RegisterGuestResponse>().await {
                                // Clear form
                                set_username.set(String::new());
                                set_email.set(String::new());
                                set_password.set(String::new());
                                set_confirm_password.set(String::new());

                                // Call success callback
                                if let Some(ref callback) = on_success {
                                    callback.run(data.username);
                                }

                                // Close modal
                                on_close.run(());
                            }
                        } else {
                            // Try to parse error message
                            if let Ok(error_data) =
                                resp.json::<serde_json::Value>().await
                            {
                                let msg = error_data
                                    .get("message")
                                    .and_then(|m| m.as_str())
                                    .unwrap_or("Registration failed");
                                set_error.set(Some(msg.to_string()));
                            } else {
                                set_error.set(Some("Registration failed".to_string()));
                            }
                        }
                    }
                    Err(e) => {
                        set_error.set(Some(format!("Network error: {}", e)));
                    }
                }
            });
        }
    };

    #[cfg(not(feature = "hydrate"))]
    let on_submit = move |_ev: leptos::ev::SubmitEvent| {};

    // Use CSS-based visibility
    let outer_class = move || {
        if open.get() {
            "fixed inset-0 z-50 flex items-center justify-center"
        } else {
            "hidden"
        }
    };

    view! {
        <div
            class=outer_class
            role="dialog"
            aria-modal="true"
            aria-labelledby="register-modal-title"
            aria-hidden=move || (!open.get()).to_string()
        >
            // Backdrop
            <div
                class="absolute inset-0 bg-black/70 backdrop-blur-sm"
                on:click=move |_| on_close_backdrop.run(())
                aria-hidden="true"
            />

            // Modal content
            <div class="relative bg-gray-800 rounded-lg shadow-2xl max-w-md w-full mx-4 p-6 border border-gray-700">
                // Header with title and close button
                <div class="flex items-center justify-between mb-4">
                    <h2 id="register-modal-title" class="text-xl font-bold text-white">
                        "Create Account"
                    </h2>
                    <button
                        type="button"
                        class="text-gray-400 hover:text-white transition-colors"
                        on:click=move |_| on_close_button.run(())
                        aria-label="Close"
                    >
                        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                        </svg>
                    </button>
                </div>

                <p class="text-gray-400 mb-6">
                    "Convert your guest account to a full account. You'll keep all your current chat history and settings."
                </p>

                // Error display
                <ErrorAlert message=Signal::derive(move || error.get()) />

                // Registration form
                <form on:submit=on_submit class="space-y-4">
                    <TextInput
                        name="username"
                        label="Username"
                        placeholder="Choose a username"
                        help_text="3-30 characters, letters, numbers, and underscores only"
                        required=true
                        minlength=3
                        maxlength=30
                        pattern=r"^[a-zA-Z0-9_]+$"
                        autocomplete="username"
                        value=Signal::derive(move || username.get())
                        on_input=Callback::new(move |val| set_username.set(val))
                    />

                    <TextInput
                        name="email"
                        label="Email"
                        input_type="email"
                        placeholder="your@email.com"
                        help_text="Optional, for account recovery"
                        required=false
                        autocomplete="email"
                        value=Signal::derive(move || email.get())
                        on_input=Callback::new(move |val| set_email.set(val))
                    />

                    <TextInput
                        name="password"
                        label="Password"
                        input_type="password"
                        placeholder="Choose a password"
                        help_text="At least 8 characters"
                        required=true
                        minlength=8
                        autocomplete="new-password"
                        value=Signal::derive(move || password.get())
                        on_input=Callback::new(move |val| set_password.set(val))
                    />

                    <TextInput
                        name="confirm_password"
                        label="Confirm Password"
                        input_type="password"
                        placeholder="Confirm your password"
                        required=true
                        minlength=8
                        autocomplete="new-password"
                        value=Signal::derive(move || confirm_password.get())
                        on_input=Callback::new(move |val| set_confirm_password.set(val))
                    />

                    <div class="pt-4">
                        <SubmitButton
                            text="Create Account"
                            loading_text="Creating account..."
                            pending=Signal::derive(move || pending.get())
                        />
                    </div>
                </form>
            </div>
        </div>
    }
}
