use leptos::prelude::*;
use leptos::task::spawn_local;
use rustelo_core_lib::{i18n::UnifiedI18n, state::use_current_language};

use super::{
    otp_service::OtpVerifyResult,
    server_fns::{server_request_otp, server_verify_otp},
};

const RESEND_COOLDOWN_SECS: u32 = 60;

/// Async sleep for WASM using gloo-timers.
async fn sleep_secs(secs: u32) {
    #[cfg(target_arch = "wasm32")]
    {
        gloo_timers::future::sleep(std::time::Duration::from_secs(u64::from(secs))).await;
    }
    #[cfg(not(target_arch = "wasm32"))]
    {
        let _ = secs; // no-op in SSR context (this code path is never reached)
    }
}

/// Second step of the OTP login flow: verify the 6-digit code.
#[component]
pub fn CodeStep(
    email: String,
    on_success: Callback<OtpVerifyResult>,
    on_back: Callback<()>,
    error_msg: RwSignal<Option<String>>,
) -> impl IntoView {
    let lang = use_current_language();
    let code = RwSignal::new(String::new());
    let loading = RwSignal::new(false);
    let countdown = RwSignal::new(RESEND_COOLDOWN_SECS);
    let resend_available = RwSignal::new(false);

    let title = Memo::new(move |_| UnifiedI18n::new(&lang.get(), "/").t("auth-otp-check-inbox"));
    let placeholder =
        Memo::new(move |_| UnifiedI18n::new(&lang.get(), "/").t("auth-otp-code-placeholder"));
    let continue_label =
        Memo::new(move |_| UnifiedI18n::new(&lang.get(), "/").t("auth-otp-continue"));
    let back_label =
        Memo::new(move |_| UnifiedI18n::new(&lang.get(), "/").t("auth-otp-back-to-email"));

    let email_for_subtitle = email.clone();
    let subtitle = Memo::new(move |_| {
        UnifiedI18n::new(&lang.get(), "/")
            .t("auth-otp-sent-to")
            .replace("{ $email }", &email_for_subtitle)
            .replace("$email", &email_for_subtitle)
    });

    // Start the resend countdown immediately on mount.
    let countdown_effect_email = email.clone();
    Effect::new(move |_| {
        let _ = countdown_effect_email.clone();
        spawn_local(async move {
            let mut remaining = RESEND_COOLDOWN_SECS;
            while remaining > 0 {
                sleep_secs(1).await;
                remaining = remaining.saturating_sub(1);
                countdown.set(remaining);
            }
            resend_available.set(true);
        });
    });

    let resend_email = email.clone();

    let on_resend = move |_| {
        if !resend_available.get() {
            return;
        }
        let e = resend_email.clone();
        let resend_lang = {
            #[cfg(target_arch = "wasm32")]
            {
                lang.get()
            }
            #[cfg(not(target_arch = "wasm32"))]
            {
                lang.get_untracked()
            }
        };
        resend_available.set(false);
        countdown.set(RESEND_COOLDOWN_SECS);
        error_msg.set(None);

        spawn_local(async move {
            if let Err(err) = server_request_otp(e, resend_lang).await {
                error_msg.set(Some(err.to_string()));
            }

            // Restart countdown.
            let mut remaining = RESEND_COOLDOWN_SECS;
            while remaining > 0 {
                sleep_secs(1).await;
                remaining = remaining.saturating_sub(1);
                countdown.set(remaining);
            }
            resend_available.set(true);
        });
    };

    let captured_email = email.clone();

    let submit = move |ev: leptos::ev::SubmitEvent| {
        ev.prevent_default();
        let e = captured_email.clone();
        let c = code.get();
        loading.set(true);
        error_msg.set(None);
        spawn_local(async move {
            match server_verify_otp(e, c).await {
                Ok(result) => on_success.run(result),
                Err(err) => error_msg.set(Some(err.to_string())),
            }
            loading.set(false);
        });
    };

    view! {
        <form on:submit=submit class="flex flex-col gap-4">
            <h2 class="text-xl font-semibold text-base-content">{title}</h2>
            <p class="text-sm text-base-content/70">{subtitle}</p>
            <input
                type="text"
                id="auth-otp-code"
                name="otp"
                inputmode="numeric"
                autocomplete="one-time-code"
                aria-label="Verification code"
                placeholder=placeholder
                maxlength="6"
                class="input input-bordered w-full text-center tracking-widest text-xl"
                prop:value=code
                on:input=move |ev| code.set(event_target_value(&ev))
            />
            <button
                type="submit"
                class="btn btn-primary w-full"
                prop:disabled=loading
            >
                {move || if loading.get() { "…".to_string() } else { continue_label.get() }}
            </button>

            // Resend button with countdown
            <button
                type="button"
                class="btn btn-sm w-full border border-base-content/20 text-base-content/60 bg-transparent hover:bg-base-content/5 disabled:opacity-40 disabled:cursor-not-allowed"
                prop:disabled=move || !resend_available.get()
                on:click=on_resend
            >
                {move || {
                    let lang_val = {
                        #[cfg(target_arch = "wasm32")]
                        { lang.get() }
                        #[cfg(not(target_arch = "wasm32"))]
                        { lang.get_untracked() }
                    };
                    let i18n = UnifiedI18n::new(&lang_val, "/");
                    if resend_available.get() {
                        i18n.t("auth-otp-resend-now")
                    } else {
                        i18n.t("auth-otp-resend-countdown")
                            .replace("{ $seconds }", &countdown.get().to_string())
                            .replace("$seconds", &countdown.get().to_string())
                    }
                }}
            </button>

            // Back link
            <button
                type="button"
                class="btn btn-ghost btn-xs dark:text-gray-400 text-base-content/50 mt-1"
                on:click=move |_| on_back.run(())
            >
                {back_label}
            </button>

            {move || error_msg.get().map(|e| view! {
                <p class="text-error text-sm">{e}</p>
            })}
        </form>
    }
}
