//! Sign-up page for new user registration.

use leptos::ev::SubmitEvent;
use leptos::prelude::*;
#[cfg(feature = "hydrate")]
use leptos::task::spawn_local;
#[cfg(feature = "hydrate")]
use leptos_router::hooks::use_navigate;
use leptos_router::hooks::use_query_map;

use crate::components::{Card, CenteredLayout, ErrorAlert, SubmitButton};
use chattyness_db::models::RealmSummary;

/// Sign-up page component.
#[component]
pub fn SignupPage() -> impl IntoView {
    #[cfg(feature = "hydrate")]
    let navigate = use_navigate();
    let query = use_query_map();

    // Form state
    let (username, set_username) = signal(String::new());
    let (display_name, set_display_name) = 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 (selected_realm, set_selected_realm) = signal(Option::<String>::None);
    let (private_realm, set_private_realm) = signal(String::new());
    let (error, set_error) = signal(Option::<String>::None);
    let (pending, set_pending) = signal(false);

    // Read query param for pre-filled realm
    Effect::new(move |_| {
        if let Some(realm) = query.read().get("realm") {
            set_private_realm.set(realm.to_string());
        }
    });

    // Fetch public realms
    let realms = LocalResource::new(move || async move {
        #[cfg(feature = "hydrate")]
        {
            use gloo_net::http::Request;
            #[derive(serde::Deserialize)]
            struct ListResponse {
                realms: Vec<RealmSummary>,
            }
            let response = Request::get("/api/realms?include_nsfw=false&limit=20")
                .send()
                .await;
            match response {
                Ok(resp) if resp.ok() => resp.json::<ListResponse>().await.ok().map(|r| r.realms),
                _ => None,
            }
        }
        #[cfg(not(feature = "hydrate"))]
        {
            None::<Vec<RealmSummary>>
        }
    });

    // Get the realm slug to use
    let realm_slug = Signal::derive(move || {
        let private = private_realm.get();
        if !private.is_empty() {
            Some(private)
        } else {
            selected_realm.get()
        }
    });

    // Handle form submission
    let on_submit = move |ev: SubmitEvent| {
        ev.prevent_default();
        set_error.set(None);

        let slug = realm_slug.get();
        if slug.is_none() {
            set_error.set(Some(
                "Please select a realm or enter a realm name".to_string(),
            ));
            return;
        }

        let uname = username.get();
        if uname.len() < 3 || uname.len() > 30 {
            set_error.set(Some("Username must be 3-30 characters".to_string()));
            return;
        }

        let dname = display_name.get();
        if dname.trim().is_empty() {
            set_error.set(Some("Display name is required".to_string()));
            return;
        }

        let pwd = password.get();
        if pwd.len() < 8 {
            set_error.set(Some("Password must be at least 8 characters".to_string()));
            return;
        }

        let confirm_pwd = confirm_password.get();
        if pwd != confirm_pwd {
            set_error.set(Some("Passwords do not match".to_string()));
            return;
        }

        set_pending.set(true);

        #[cfg(feature = "hydrate")]
        {
            use chattyness_db::models::{SignupRequest, SignupResponse};
            use gloo_net::http::Request;

            let navigate = navigate.clone();
            let email_val = email.get();
            let email_opt = if email_val.trim().is_empty() {
                None
            } else {
                Some(email_val)
            };

            spawn_local(async move {
                let request = SignupRequest {
                    username: uname,
                    email: email_opt,
                    display_name: dname,
                    password: pwd,
                    confirm_password: confirm_pwd,
                    realm_slug: slug.unwrap(),
                    birthday: None,
                    gender_preference: None,
                    age_category: None,
                };

                let response = Request::post("/api/auth/signup")
                    .json(&request)
                    .unwrap()
                    .send()
                    .await;

                set_pending.set(false);

                match response {
                    Ok(resp) if resp.ok() => {
                        if let Ok(signup_resp) = resp.json::<SignupResponse>().await {
                            navigate(&signup_resp.redirect_url, Default::default());
                        }
                    }
                    Ok(resp) => {
                        #[derive(serde::Deserialize)]
                        struct ErrorResp {
                            error: String,
                        }
                        let status = resp.status();
                        if let Ok(err) = resp.json::<ErrorResp>().await {
                            set_error.set(Some(err.error));
                        } else if status == 409 {
                            set_error.set(Some("Username or email already taken".to_string()));
                        } else if status == 404 {
                            set_error.set(Some("Realm not found".to_string()));
                        } else {
                            set_error.set(Some("Sign up failed. Please try again.".to_string()));
                        }
                    }
                    Err(_) => {
                        set_error.set(Some(
                            "Network error. Please check your connection.".to_string(),
                        ));
                    }
                }
            });
        }
    };

    view! {
        <CenteredLayout>
            <div class="w-full max-w-lg">
                <div class="text-center mb-8">
                    <h1 class="text-3xl font-bold text-white mb-2">"Join Chattyness"</h1>
                    <p class="text-gray-400">"Create your account and join a realm"</p>
                </div>

                <Card class="p-6">
                    <form on:submit=on_submit class="space-y-6">
                        // Realm selection
                        <fieldset>
                            <legend class="text-sm font-medium text-gray-300 mb-3">
                                "Choose a Realm"
                            </legend>

                            <Suspense fallback=move || {
                                view! { <p class="text-gray-400">"Loading realms..."</p> }
                            }>
                                {move || {
                                    realms
                                        .get()
                                        .map(|maybe_realms: Option<Vec<RealmSummary>>| {
                                            match maybe_realms {
                                                Some(realms) if !realms.is_empty() => {
                                                    view! {
                                                        <div class="space-y-2 max-h-48 overflow-y-auto mb-4">
                                                            {realms
                                                                .into_iter()
                                                                .map(|realm| {
                                                                    let slug = realm.slug.clone();
                                                                    let slug_for_click = slug.clone();
                                                                    let is_selected = Signal::derive(move || {
                                                                        selected_realm.get() == Some(slug.clone())
                                                                    });
                                                                    view! {
                                                                        <button
                                                                            type="button"
                                                                            class=move || {
                                                                                let base = "w-full text-left p-3 rounded-lg border transition-colors";
                                                                                if is_selected.get() {
                                                                                    format!("{} border-blue-500 bg-blue-500/10", base)
                                                                                } else {
                                                                                    format!(
                                                                                        "{} border-gray-700 hover:border-gray-600 hover:bg-gray-700/50",
                                                                                        base,
                                                                                    )
                                                                                }
                                                                            }
                                                                            on:click=move |_| {
                                                                                set_selected_realm
                                                                                    .set(Some(slug_for_click.clone()));
                                                                                set_private_realm.set(String::new());
                                                                            }
                                                                        >
                                                                            <div class="flex items-center justify-between">
                                                                                <div>
                                                                                    <span class="text-white font-medium">
                                                                                        {realm.name.clone()}
                                                                                    </span>
                                                                                    <span class="text-gray-500 text-sm ml-2">
                                                                                        {format!("/{}", realm.slug)}
                                                                                    </span>
                                                                                </div>
                                                                                <span class="text-gray-400 text-sm">
                                                                                    {realm.member_count}
                                                                                    " members"
                                                                                </span>
                                                                            </div>
                                                                        </button>
                                                                    }
                                                                })
                                                                .collect_view()}
                                                        </div>
                                                    }
                                                        .into_any()
                                                }
                                                _ => {
                                                    view! {
                                                        <p class="text-gray-400 mb-4">
                                                            "No public realms available"
                                                        </p>
                                                    }
                                                        .into_any()
                                                }
                                            }
                                        })
                                }}
                            </Suspense>

                            <div class="relative">
                                <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                    <span class="text-gray-500">"/"</span>
                                </div>
                                <input
                                    type="text"
                                    placeholder="Or enter a realm name"
                                    class="input-base pl-6"
                                    prop:value=move || private_realm.get()
                                    on:input=move |ev| {
                                        set_private_realm.set(event_target_value(&ev));
                                        set_selected_realm.set(None);
                                    }
                                />
                            </div>
                        </fieldset>

                        // Account details
                        <div class="space-y-4">
                            <div>
                                <label
                                    for="username"
                                    class="block text-sm font-medium text-gray-300 mb-2"
                                >
                                    "Username"
                                    <span class="text-red-400" aria-hidden="true">"*"</span>
                                </label>
                                <input
                                    type="text"
                                    id="username"
                                    name="username"
                                    required=true
                                    autocomplete="username"
                                    minlength=3
                                    maxlength=30
                                    pattern="[a-z][a-z0-9_]*"
                                    class="input-base"
                                    placeholder="lowercase letters, numbers, underscores"
                                    prop:value=move || username.get()
                                    on:input=move |ev| set_username.set(event_target_value(&ev))
                                />
                                <p class="text-gray-500 text-xs mt-1">
                                    "3-30 characters, starts with a letter"
                                </p>
                            </div>

                            <div>
                                <label
                                    for="display_name"
                                    class="block text-sm font-medium text-gray-300 mb-2"
                                >
                                    "Display Name"
                                    <span class="text-red-400" aria-hidden="true">"*"</span>
                                </label>
                                <input
                                    type="text"
                                    id="display_name"
                                    name="display_name"
                                    required=true
                                    maxlength=50
                                    class="input-base"
                                    placeholder="How others will see you"
                                    prop:value=move || display_name.get()
                                    on:input=move |ev| set_display_name.set(event_target_value(&ev))
                                />
                            </div>

                            <div>
                                <label
                                    for="email"
                                    class="block text-sm font-medium text-gray-300 mb-2"
                                >
                                    "Email"
                                    <span class="text-gray-500 text-xs ml-1">"(optional)"</span>
                                </label>
                                <input
                                    type="email"
                                    id="email"
                                    name="email"
                                    autocomplete="email"
                                    class="input-base"
                                    placeholder="your@email.com"
                                    prop:value=move || email.get()
                                    on:input=move |ev| set_email.set(event_target_value(&ev))
                                />
                            </div>

                            <div>
                                <label
                                    for="password"
                                    class="block text-sm font-medium text-gray-300 mb-2"
                                >
                                    "Password"
                                    <span class="text-red-400" aria-hidden="true">"*"</span>
                                </label>
                                <input
                                    type="password"
                                    id="password"
                                    name="password"
                                    required=true
                                    minlength=8
                                    autocomplete="new-password"
                                    class="input-base"
                                    placeholder="At least 8 characters"
                                    prop:value=move || password.get()
                                    on:input=move |ev| set_password.set(event_target_value(&ev))
                                />
                            </div>

                            <div>
                                <label
                                    for="confirm_password"
                                    class="block text-sm font-medium text-gray-300 mb-2"
                                >
                                    "Confirm Password"
                                    <span class="text-red-400" aria-hidden="true">"*"</span>
                                </label>
                                <input
                                    type="password"
                                    id="confirm_password"
                                    name="confirm_password"
                                    required=true
                                    minlength=8
                                    autocomplete="new-password"
                                    class="input-base"
                                    prop:value=move || confirm_password.get()
                                    on:input=move |ev| {
                                        set_confirm_password.set(event_target_value(&ev))
                                    }
                                />
                            </div>
                        </div>

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

                        <SubmitButton
                            text="Create Account"
                            loading_text="Creating account..."
                            pending=Signal::derive(move || pending.get())
                        />

                        <p class="text-center text-gray-400 text-sm">
                            "Already have an account? "
                            <a href="/" class="text-blue-400 hover:underline">
                                "Sign in"
                            </a>
                        </p>
                    </form>
                </Card>
            </div>
        </CenteredLayout>
    }
}
