use leptos::prelude::*;
use leptos::task::spawn_local;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{PublicKeyCredential, CredentialCreationOptions, PublicKeyCredentialCreationOptions};
use crate::services::auth_service::{AuthService, WebAuthnCredential, WebAuthnAuthenticatorResponse};

#[component]
pub fn MfaSetupWebauthn(
    #[prop(into)] access_token: Signal<String>,
    #[prop(optional)] on_complete: Option<Box<dyn Fn() + Send + Sync>>,
) -> impl IntoView {
    let (device_name, set_device_name) = signal(String::new());
    let (registering, set_registering) = signal(false);
    let (error_message, set_error_message) = signal(None::<String>);
    let (success, set_success) = signal(false);

    let auth_service = AuthService::new();

    let start_registration = move |_| {
        set_registering.set(true);
        set_error_message.set(None);

        let auth_service = auth_service.clone();
        let token = access_token.get();
        let name = device_name.get();

        spawn_local(async move {
            // Step 1: Get challenge from server
            let challenge = match auth_service.start_webauthn_registration(token.clone()).await {
                Ok(c) => c,
                Err(e) => {
                    set_error_message.set(Some(format!("Failed to start registration: {}", e)));
                    set_registering.set(false);
                    return;
                }
            };

            // Step 2: Create credential with WebAuthn API
            let credential_result = create_webauthn_credential(&challenge).await;

            let credential = match credential_result {
                Ok(c) => c,
                Err(e) => {
                    set_error_message.set(Some(format!("WebAuthn failed: {}", e)));
                    set_registering.set(false);
                    return;
                }
            };

            // Step 3: Send credential to server
            match auth_service.finish_webauthn_registration(token, credential).await {
                Ok(_) => {
                    set_success.set(true);
                    if let Some(callback) = &on_complete {
                        callback();
                    }
                }
                Err(e) => {
                    set_error_message.set(Some(format!("Failed to complete registration: {}", e)));
                }
            }

            set_registering.set(false);
        });
    };

    view! {
        <div class="max-w-2xl mx-auto">
            // Error alert
            {move || error_message.get().map(|err| view! {
                <div class="alert alert-error shadow-lg mb-4">
                    <div>
                        <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
                        </svg>
                        <span>{err}</span>
                    </div>
                </div>
            })}

            // Success state
            <Show
                when=move || success.get()
                fallback=move || view! {
                    <div class="card bg-base-100 shadow-xl">
                        <div class="card-body">
                            <h2 class="card-title text-2xl">"Setup Security Key (WebAuthn)"</h2>

                            <div class="space-y-4">
                                <div class="alert alert-info">
                                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                                    </svg>
                                    <span>"Use a physical security key like YubiKey or your device's built-in biometric authentication (Touch ID, Face ID, Windows Hello)."</span>
                                </div>

                                <div class="prose">
                                    <h3>"How it works:"</h3>
                                    <ol>
                                        <li>"Insert your security key or prepare your biometric device"</li>
                                        <li>"Click the registration button"</li>
                                        <li>"Follow your browser's prompts to register"</li>
                                        <li>"Tap your key or use biometric authentication when prompted"</li>
                                    </ol>
                                </div>

                                <div class="divider"></div>

                                <div class="form-control">
                                    <label class="label" for="device-name">
                                        <span class="label-text font-medium">"Device Name (Optional)"</span>
                                    </label>
                                    <input
                                        type="text"
                                        id="device-name"
                                        class="input input-bordered w-full"
                                        placeholder="e.g., YubiKey 5C, MacBook Touch ID"
                                        on:input=move |ev| {
                                            set_device_name.set(event_target_value(&ev));
                                        }
                                        prop:value=device_name
                                    />
                                    <label class="label">
                                        <span class="label-text-alt">"Give your security key a name to identify it later"</span>
                                    </label>
                                </div>

                                // Illustration
                                <div class="flex justify-center py-8">
                                    <div class="text-center">
                                        <div class="inline-flex items-center justify-center w-32 h-32 bg-primary/10 rounded-full mb-4">
                                            <svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
                                            </svg>
                                        </div>
                                        <p class="text-base-content/70">"Have your security key ready"</p>
                                    </div>
                                </div>
                            </div>

                            <div class="card-actions justify-end mt-6">
                                <button
                                    class="btn btn-primary btn-lg"
                                    on:click=start_registration
                                    disabled=move || registering.get()
                                >
                                    {move || if registering.get() {
                                        view! {
                                            <span class="loading loading-spinner loading-sm"></span>
                                            " Waiting for device..."
                                        }.into_view()
                                    } else {
                                        view! {
                                            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
                                            </svg>
                                            "Register Security Key"
                                        }.into_view()
                                    }}
                                </button>
                            </div>

                            <Show when=move || registering.get()>
                                <div class="alert alert-warning mt-4">
                                    <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                                    </svg>
                                    <div>
                                        <p class="font-medium">"Follow your browser's prompts"</p>
                                        <p class="text-sm">"You may need to tap your security key or use biometric authentication"</p>
                                    </div>
                                </div>
                            </Show>
                        </div>
                    </div>
                }
            >
                <div class="card bg-base-100 shadow-xl">
                    <div class="card-body items-center text-center">
                        <div class="inline-flex items-center justify-center w-24 h-24 bg-success/10 rounded-full mb-4">
                            <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-success" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
                            </svg>
                        </div>

                        <h2 class="card-title text-2xl">"Security Key Registered!"</h2>
                        <p class="text-base-content/70">
                            "Your security key has been successfully registered. You can now use it to log in."
                        </p>

                        <div class="card-actions mt-6">
                            <button class="btn btn-primary" on:click=move |_| {
                                if let Some(callback) = &on_complete {
                                    callback();
                                }
                            }>
                                "Done"
                            </button>
                        </div>
                    </div>
                </div>
            </Show>
        </div>
    }
}

// WebAuthn credential creation helper
async fn create_webauthn_credential(challenge: &crate::services::auth_service::WebAuthnChallengeResponse) -> Result<WebAuthnCredential, String> {
    let window = web_sys::window().ok_or("No window object")?;
    let navigator = window.navigator();
    let credentials = navigator.credentials();

    // Convert challenge to Uint8Array
    let challenge_bytes = js_sys::Uint8Array::from(challenge.challenge.as_bytes());
    let user_id_bytes = js_sys::Uint8Array::from(challenge.user_id.as_bytes());

    // Create PublicKeyCredentialCreationOptions
    let options = web_sys::PublicKeyCredentialCreationOptions::new(
        &challenge_bytes,
        &create_rp_object(&challenge.rp_id),
        &create_user_object(&challenge.user_id, &challenge.user_name, user_id_bytes),
        &create_pub_key_cred_params(),
    );

    // Set timeout (30 seconds)
    options.set_timeout(30000);

    // Set attestation preference
    options.set_attestation(web_sys::AttestationConveyancePreference::None);

    // Create CredentialCreationOptions
    let mut credential_options = CredentialCreationOptions::new();
    credential_options.public_key(&options);

    // Call WebAuthn API
    let promise = credentials.create_with_options(&credential_options)
        .map_err(|e| format!("Failed to create credential: {:?}", e))?;

    let result = wasm_bindgen_futures::JsFuture::from(promise).await
        .map_err(|e| format!("WebAuthn operation failed: {:?}", e))?;

    // Convert to PublicKeyCredential
    let credential = result.dyn_into::<PublicKeyCredential>()
        .map_err(|_| "Failed to cast to PublicKeyCredential")?;

    // Extract credential data
    let id = credential.id();
    let raw_id = js_sys::Uint8Array::new(&credential.raw_id()).to_vec();

    let response = credential.response();
    let attestation_response = response.dyn_into::<web_sys::AuthenticatorAttestationResponse>()
        .map_err(|_| "Failed to cast to AuthenticatorAttestationResponse")?;

    let attestation_object = js_sys::Uint8Array::new(&attestation_response.attestation_object()).to_vec();
    let client_data_json = js_sys::Uint8Array::new(&attestation_response.client_data_json()).to_vec();

    Ok(WebAuthnCredential {
        id,
        raw_id,
        response: WebAuthnAuthenticatorResponse {
            attestation_object,
            client_data_json,
        },
    })
}

fn create_rp_object(rp_id: &str) -> js_sys::Object {
    let obj = js_sys::Object::new();
    js_sys::Reflect::set(&obj, &"id".into(), &rp_id.into()).unwrap();
    js_sys::Reflect::set(&obj, &"name".into(), &"Control Center".into()).unwrap();
    obj
}

fn create_user_object(user_id: &str, user_name: &str, id_bytes: js_sys::Uint8Array) -> js_sys::Object {
    let obj = js_sys::Object::new();
    js_sys::Reflect::set(&obj, &"id".into(), &id_bytes).unwrap();
    js_sys::Reflect::set(&obj, &"name".into(), &user_name.into()).unwrap();
    js_sys::Reflect::set(&obj, &"displayName".into(), &user_name.into()).unwrap();
    obj
}

fn create_pub_key_cred_params() -> js_sys::Array {
    let array = js_sys::Array::new();

    // ES256 (ECDSA with SHA-256)
    let param = js_sys::Object::new();
    js_sys::Reflect::set(&param, &"type".into(), &"public-key".into()).unwrap();
    js_sys::Reflect::set(&param, &"alg".into(), &(-7).into()).unwrap();
    array.push(&param);

    // RS256 (RSASSA-PKCS1-v1_5 with SHA-256)
    let param2 = js_sys::Object::new();
    js_sys::Reflect::set(&param2, &"type".into(), &"public-key".into()).unwrap();
    js_sys::Reflect::set(&param2, &"alg".into(), &(-257).into()).unwrap();
    array.push(&param2);

    array
}
