//! Login page for realm users.

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 crate::components::{Card, CenteredLayout, ErrorAlert, JoinRealmModal, SubmitButton};
use chattyness_db::models::RealmSummary;

/// Main login page component.
#[component]
pub fn LoginPage() -> impl IntoView {
    view! {
        <CenteredLayout>
            <div class="w-full max-w-lg">
                // Logo and title
                <div class="text-center mb-8">
                    <h1 class="text-3xl font-bold text-white mb-2">
                        <span aria-hidden="true">"Chattyness"</span>
                    </h1>
                    <p class="text-gray-400">"Sign in to explore virtual community spaces"</p>
                </div>

                <Card class="p-6">
                    <RealmLoginForm />
                </Card>
            </div>
        </CenteredLayout>
    }
}

/// Realm login form component.
#[component]
fn RealmLoginForm() -> impl IntoView {
    #[cfg(feature = "hydrate")]
    let navigate = use_navigate();
    #[cfg(feature = "hydrate")]
    let navigate_for_submit = navigate.clone();
    #[cfg(feature = "hydrate")]
    let navigate_for_join = navigate.clone();
    #[cfg(feature = "hydrate")]
    let navigate_for_guest = navigate.clone();

    // Form state
    let (username, set_username) = signal(String::new());
    let (password, set_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);
    let (guest_pending, set_guest_pending) = signal(false);

    // Join modal state
    let (show_join_modal, set_show_join_modal) = signal(false);
    let (join_pending, set_join_pending) = signal(false);
    let (pending_realm, set_pending_realm) = signal(Option::<RealmSummary>::None);

    // 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 || {
        if !private_realm.get().is_empty() {
            Some(private_realm.get())
        } else {
            selected_realm.get()
        }
    });

    // Handle login 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 private realm name".to_string(),
            ));
            return;
        }

        #[cfg(feature = "hydrate")]
        let slug = slug.unwrap();
        let uname = username.get();
        let pwd = password.get();

        if uname.is_empty() || pwd.is_empty() {
            set_error.set(Some("Username and password are required".to_string()));
            return;
        }

        set_pending.set(true);

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

            let navigate = navigate_for_submit.clone();
            spawn_local(async move {
                let request = LoginRequest {
                    username: uname,
                    password: pwd,
                    login_type: LoginType::Realm,
                    realm_slug: Some(slug),
                };

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

                set_pending.set(false);

                match response {
                    Ok(resp) if resp.ok() => {
                        if let Ok(login_resp) = resp.json::<LoginResponse>().await {
                            if login_resp.requires_pw_reset {
                                navigate(&login_resp.redirect_url, Default::default());
                            } else if login_resp.is_member == Some(false) {
                                if let Some(realm) = login_resp.realm {
                                    set_pending_realm.set(Some(realm));
                                    set_show_join_modal.set(true);
                                }
                            } else {
                                navigate(&login_resp.redirect_url, Default::default());
                            }
                        }
                    }
                    Ok(resp) => {
                        let status = resp.status();
                        if status == 401 {
                            set_error.set(Some("Invalid username or password".to_string()));
                        } else if status == 403 {
                            set_error.set(Some("Your account is suspended or banned".to_string()));
                        } else {
                            set_error.set(Some("Login failed. Please try again.".to_string()));
                        }
                    }
                    Err(_) => {
                        set_error.set(Some(
                            "Network error. Please check your connection.".to_string(),
                        ));
                    }
                }
            });
        }
    };

    // Handle join confirmation
    let on_join_confirm = move |_| {
        if pending_realm.get().is_some() {
            set_join_pending.set(true);

            #[cfg(feature = "hydrate")]
            {
                use chattyness_db::models::JoinRealmRequest;
                use gloo_net::http::Request;

                let realm = pending_realm.get().unwrap();
                let navigate = navigate_for_join.clone();
                let realm_id = realm.id;
                let realm_slug = realm.slug.clone();

                spawn_local(async move {
                    let request = JoinRealmRequest { realm_id };

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

                    set_join_pending.set(false);
                    set_show_join_modal.set(false);

                    match response {
                        Ok(resp) if resp.ok() => {
                            navigate(&format!("/realms/{}", realm_slug), Default::default());
                        }
                        Ok(resp) => {
                            let status = resp.status();
                            if status == 403 {
                                set_error.set(Some("Cannot join this realm".to_string()));
                            } else {
                                set_error.set(Some(
                                    "Failed to join realm. Please try again.".to_string(),
                                ));
                            }
                        }
                        Err(_) => {
                            set_error.set(Some(
                                "Network error. Please check your connection.".to_string(),
                            ));
                        }
                    }
                });
            }
        }
    };

    let on_join_cancel = move |_| {
        set_show_join_modal.set(false);
        set_pending_realm.set(None);
    };

    // Handle guest login
    let on_guest_click = move |_| {
        set_error.set(None);

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

        set_guest_pending.set(true);

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

            let navigate = navigate_for_guest.clone();
            let realm_slug_val = slug.unwrap();

            spawn_local(async move {
                let request = GuestLoginRequest {
                    realm_slug: realm_slug_val,
                };

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

                set_guest_pending.set(false);

                match response {
                    Ok(resp) if resp.ok() => {
                        if let Ok(guest_resp) = resp.json::<GuestLoginResponse>().await {
                            navigate(&guest_resp.redirect_url, Default::default());
                        }
                    }
                    Ok(resp) => {
                        #[derive(serde::Deserialize)]
                        struct ErrorResp {
                            error: String,
                        }
                        if let Ok(err) = resp.json::<ErrorResp>().await {
                            set_error.set(Some(err.error));
                        } else {
                            set_error.set(Some(
                                "Guest access not available for this realm".to_string(),
                            ));
                        }
                    }
                    Err(_) => {
                        set_error.set(Some(
                            "Network error. Please check your connection.".to_string(),
                        ));
                    }
                }
            });
        }
    };

    view! {
        <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>

                // Public realm list
                <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.current_user_count}
                                                                        " online"
                                                                    </span>
                                                                </div>
                                                                {realm
                                                                    .tagline
                                                                    .as_ref()
                                                                    .map(|t: &String| {
                                                                        view! {
                                                                            <p class="text-gray-400 text-sm mt-1">{t.clone()}</p>
                                                                        }
                                                                    })}
                                                            </button>
                                                        }
                                                    })
                                                    .collect_view()}
                                            </div>
                                        }
                                            .into_any()
                                    }
                                    _ => {
                                        view! {
                                            <p class="text-gray-400 mb-4">"No public realms available"</p>
                                        }
                                            .into_any()
                                    }
                                }
                            })
                    }}
                </Suspense>

                // Private realm input
                <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 private 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>

            // Credentials
            <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"
                        class="input-base"
                        prop:value=move || username.get()
                        on:input=move |ev| set_username.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
                        autocomplete="current-password"
                        class="input-base"
                        prop:value=move || password.get()
                        on:input=move |ev| set_password.set(event_target_value(&ev))
                    />
                </div>
            </div>

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

            // Submit button
            <SubmitButton
                text="Enter Realm"
                loading_text="Signing in..."
                pending=Signal::derive(move || pending.get())
            />

            // Divider
            <div class="relative">
                <div class="absolute inset-0 flex items-center">
                    <div class="w-full border-t border-gray-700"></div>
                </div>
                <div class="relative flex justify-center text-sm">
                    <span class="px-2 bg-gray-800 text-gray-400">"or"</span>
                </div>
            </div>

            // Guest button
            <button
                type="button"
                class="w-full py-3 px-4 border border-gray-600 rounded-lg text-gray-300 hover:bg-gray-700 hover:border-gray-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                disabled=move || guest_pending.get() || realm_slug.get().is_none()
                on:click=on_guest_click
            >
                {move || {
                    if guest_pending.get() { "Joining as guest..." } else { "Continue as Guest" }
                }}
            </button>

            // Sign up link
            <p class="text-center text-gray-400 text-sm">
                "Don't have an account? "
                <a href="/signup" class="text-blue-400 hover:underline">
                    "Sign up"
                </a>
            </p>
        </form>

        // Join modal
        {
            let on_join_confirm = on_join_confirm.clone();
            let on_join_cancel = on_join_cancel.clone();
            move || {
                let on_join_confirm = on_join_confirm.clone();
                let on_join_cancel = on_join_cancel.clone();
                pending_realm
                    .get()
                    .map(|realm| {
                        view! {
                            <JoinRealmModal
                                open=Signal::derive(move || show_join_modal.get())
                                realm_name=realm.name.clone()
                                realm_slug=realm.slug.clone()
                                pending=Signal::derive(move || join_pending.get())
                                on_confirm=Callback::new(on_join_confirm.clone())
                                on_cancel=Callback::new(on_join_cancel.clone())
                            />
                        }
                    })
            }
        }
    }
}
