use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use rustelo_core_lib::auth::Login2FARequest;

use crate::auth::context::use_auth;
use crate::utils::api_request;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiResponse<T> {
  pub success: bool,
  pub data: Option<T>,
  pub message: Option<String>,
  pub errors: Option<Vec<String>>,
}

#[component]
pub fn TwoFactorLoginForm(
  /// The email address from the first login step
  email: String,
  /// Whether to remember the user
  remember_me: bool,
  /// Callback when login is successful
  #[prop(optional)]
  on_success: Option<Callback<()>>,
  /// Callback when user wants to go back to regular login
  #[prop(optional)]
  on_back: Option<Callback<()>>,
) -> impl IntoView {
  let (code, set_code) = signal(String::new());
  let (error_message, set_error_message) = signal(Option::<String>::None);
  let (is_submitting, set_is_submitting) = signal(false);
  let (is_backup_code, set_is_backup_code) = signal(false);

  let auth_context = use_auth();

  let submit_2fa = Action::new(move |request: &Login2FARequest| {
    let request = request.clone();
    let auth_context = auth_context.clone();

    async move {
      set_is_submitting.set(true);
      set_error_message.set(None);

      match api_request::<Login2FARequest, ApiResponse<rustelo_core_lib::auth::AuthResponse>>(
        "/api/auth/login/2fa",
        "POST",
        Some(request),
      )
      .await
      {
        Ok(response) => {
          if response.success {
            if let Some(auth_response) = response.data {
              // Update auth context with the successful login
              // Note: You'll need to implement login_success method in auth context
              // auth_context.login_success(auth_response.user, auth_response.access_token);

              // Call success callback if provided
              if let Some(callback) = on_success {
                callback(());
              }
            }
          } else {
            let error_msg = response.message.unwrap_or_else(|| {
              response
                .errors
                .map(|errs| errs.join(", "))
                .unwrap_or_else(|| "Invalid 2FA code".to_string())
            });
            set_error_message.set(Some(error_msg));
          }
        }
        Err(e) => {
          set_error_message.set(Some(format!("Network error: {}", e)));
        }
      }

      set_is_submitting.set(false);
    }
  });

  let handle_submit = move |ev: leptos::ev::SubmitEvent| {
    ev.prevent_default();

    let code_value = code.get().trim().to_string();
    if code_value.is_empty() {
      set_error_message.set(Some("Please enter your 2FA code".to_string()));
      return;
    }

    let request = Login2FARequest {
      email: email.clone(),
      code: code_value,
      remember_me,
    };

    submit_2fa.dispatch(request);
  };

  let handle_back = move |_| {
    if let Some(callback) = on_back {
      callback(());
    }
  };

  let toggle_backup_code = move |_| {
    set_is_backup_code.set(!is_backup_code.get());
    set_code.set(String::new());
    set_error_message.set(None);
  };

  view! {
    <div class="max-w-md mx-auto ds-bg ds-rounded-lg ds-shadow-md p-ds-6">
      <div class="text-center mb-6">
        <h1 class="text-2xl font-bold ds-text mb-2">
          "Two-Factor Authentication"
        </h1>
        <p class="ds-text-secondary">
          "Enter the code from your authenticator app"
        </p>
      </div>

      // Show the email being used
      <div class="mb-ds-4 p-3 ds-rounded-lg">
        <p class="ds-caption ds-text-secondary">
          "Signing in as: "
          <span class="font-medium ds-text">{email.clone()}</span>
        </p>
      </div>

      // Error message
      {move || {
        if let Some(msg) = error_message.get() {
          view! {
            <div class="mb-ds-4 p-3 bg-red-50 border border-red-200 ds-rounded-lg">
              <p class="ds-caption ds-text">{msg}</p>
            </div>
          }.into_any()
        } else {
          view! { <div></div> }.into_any()
        }
      }}

      <form on:submit=handle_submit class="space-y-4">
        <div>
          <label class="block ds-caption font-medium ds-text-secondary mb-2">
            {move || if is_backup_code.get() {
              "Backup Code"
            } else {
              "Authentication Code"
            }}
          </label>
          <input
            type="text"
            class="w-full px-3 py-2 border ds-border ds-rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-center ds-body font-mono"
            placeholder=move || if is_backup_code.get() {
              "Enter backup code"
            } else {
              "000000"
            }
            maxlength=move || if is_backup_code.get() { "8" } else { "6" }
            autocomplete="one-time-code"
            prop:value=code
            on:input=move |ev| set_code.set(event_target_value(&ev))
            required
            autofocus
          />
          <p class="mt-1 text-xs ds-text-muted">
            {move || if is_backup_code.get() {
              "Use one of your 8-digit backup codes"
            } else {
              "Enter the 6-digit code from your authenticator app"
            }}
          </p>
        </div>

        <div class="flex items-center justify-between">
          <button
            type="button"
            class="ds-caption text-blue-600 hover:text-blue-800 underline"
            on:click=toggle_backup_code
          >
            {move || if is_backup_code.get() {
              "Use authenticator code"
            } else {
              "Use backup code"
            }}
          </button>

          <button
            type="button"
            class="ds-caption ds-text-muted hover:ds-text-secondary underline"
            on:click=handle_back
          >
            "Back to login"
          </button>
        </div>

        <button
          type="submit"
          class="w-full bg-ds-brand-primary ds-text py-2 px-4 ds-rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
          disabled=move || is_submitting.get()
        >
          {move || if is_submitting.get() {
            "Verifying..."
          } else {
            "Sign In"
          }}
        </button>
      </form>

      // Help text
      <div class="mt-ds-6 text-center">
        <p class="text-xs ds-text-muted">
          "Lost your device? "
          <a href="/help/2fa" class="text-blue-600 hover:text-blue-800 underline">
            "Contact support"
          </a>
        </p>
      </div>
    </div>
  }
}

#[component]
pub fn TwoFactorLoginPage() -> impl IntoView {
  // Simple implementation - in a real app you'd get these from URL params or state
  let email = "user@example.com".to_string();
  let remember_me = false;

  let handle_back = move |_| {
    if let Some(window) = web_sys::window() {
      let _ = window.location().set_href("/login");
    }
  };

  view! {
    <div class="min-h-screen flex items-center justify-center py-12 px-4 sm:ds-container ">
      <TwoFactorLoginForm
        email=email
        remember_me=remember_me
        on_back=handle_back
      />
    </div>
  }
}
