use std::sync::Arc;

use leptos::prelude::*;
// use leptos_router::use_navigate;
use rustelo_core_lib::auth::User;

use crate::i18n::use_i18n;
// wasm_bindgen_futures::spawn_local removed since not used in placeholder
// implementation

#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn spawn_local<F>(_fut: F)
where
    F: std::future::Future<Output = ()> + 'static,
{
    // On server side, don't execute async operations that require browser APIs
    // These operations should only run in the browser
}

#[derive(Clone, Debug, Default)]
pub struct AuthState {
    pub user: Option<User>,
    pub is_loading: bool,
    pub error: Option<String>,
    pub requires_2fa: bool,
    pub pending_2fa_email: Option<String>,
}

/// Type alias for profile update callback
pub type ProfileUpdateFn = Arc<dyn Fn(String, Option<String>, Option<String>) + Send + Sync>;

#[derive(Clone)]
pub struct AuthActions {
    pub login: Arc<dyn Fn(String, String, bool) + Send + Sync>,
    pub login_with_2fa: Arc<dyn Fn(String, String, bool) + Send + Sync>,
    pub logout: Arc<dyn Fn() + Send + Sync>,
    pub register: Arc<dyn Fn(String, String, String, Option<String>) + Send + Sync>,
    pub refresh_token: Arc<dyn Fn() + Send + Sync>,
    pub update_profile: ProfileUpdateFn,
    pub change_password: Arc<dyn Fn(String, String) + Send + Sync>,
    pub clear_error: Arc<dyn Fn() + Send + Sync>,
    pub clear_2fa_state: Arc<dyn Fn() + Send + Sync>,
}

#[derive(Clone)]
pub struct AuthContext {
    pub state: ReadSignal<AuthState>,
    pub actions: AuthActions,
}

impl AuthContext {
    pub fn is_authenticated(&self) -> bool {
        self.state.get().user.is_some()
    }

    pub fn is_loading(&self) -> bool {
        self.state.get().is_loading
    }

    pub fn user(&self) -> Option<User> {
        self.state.get().user
    }

    pub fn error(&self) -> Option<String> {
        self.state.get().error
    }

    pub fn requires_2fa(&self) -> bool {
        self.state.get().requires_2fa
    }

    pub fn pending_2fa_email(&self) -> Option<String> {
        self.state.get().pending_2fa_email
    }

    pub fn has_role(&self, role: &rustelo_core_lib::auth::Role) -> bool {
        self.state
            .get()
            .user
            .as_ref()
            .is_some_and(|user| user.has_role(role))
    }

    pub fn has_permission(&self, permission: &rustelo_core_lib::auth::Permission) -> bool {
        self.state
            .get()
            .user
            .as_ref()
            .is_some_and(|user| user.has_permission(permission))
    }

    pub fn is_admin(&self) -> bool {
        self.state
            .get()
            .user
            .as_ref()
            .is_some_and(|user| user.is_admin())
    }

    pub fn login_success(&self, _user: User, token: String) {
        // Store token in localStorage
        if let Some(window) = web_sys::window() {
            if let Ok(Some(storage)) = window.local_storage() {
                let _ = storage.set_item("auth_token", &token);
            }
        }
    }
}

/// Helper function to map server errors to translation keys
#[allow(dead_code)]
fn get_error_translation_key(error_text: &str) -> &str {
    let error_lower = error_text.to_lowercase();

    if error_lower.contains("invalid credentials") {
        "invalid-credentials"
    } else if error_lower.contains("user not found") {
        "user-not-found"
    } else if error_lower.contains("email already exists") {
        "email-already-exists"
    } else if error_lower.contains("username already exists") {
        "username-already-exists"
    } else if error_lower.contains("invalid token") {
        "invalid-token"
    } else if error_lower.contains("token expired") {
        "token-expired"
    } else if error_lower.contains("insufficient permissions") {
        "insufficient-permissions"
    } else if error_lower.contains("account not verified") {
        "account-not-verified"
    } else if error_lower.contains("account suspended") {
        "account-suspended"
    } else if error_lower.contains("rate limit exceeded") {
        "rate-limit-exceeded"
    } else if error_lower.contains("oauth") {
        "oauth-error"
    } else if error_lower.contains("database") {
        "database-error"
    } else if error_lower.contains("validation") {
        "validation-error"
    } else if error_lower.contains("login failed") {
        "login-failed"
    } else if error_lower.contains("registration failed") {
        "registration-failed"
    } else if error_lower.contains("session expired") {
        "session-expired"
    } else if error_lower.contains("profile") && error_lower.contains("failed") {
        "profile-update-failed"
    } else if error_lower.contains("password") && error_lower.contains("failed") {
        "password-change-failed"
    } else if error_lower.contains("network") {
        "network-error"
    } else if error_lower.contains("server") {
        "server-error"
    } else if error_lower.contains("internal") {
        "internal-error"
    } else {
        "unknown-error"
    }
}

/// Helper function to parse server error response and get localized message
#[allow(dead_code)]
fn parse_error_response(response_text: &str, i18n: &crate::i18n::UseI18n) -> String {
    // Try to parse as JSON first
    if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(response_text) {
        if let Some(message) = json_value.get("message").and_then(|m| m.as_str()) {
            let key = get_error_translation_key(message);
            return i18n.t(key);
        }
        if let Some(errors) = json_value.get("errors").and_then(|e| e.as_array()) {
            if let Some(first_error) = errors.first().and_then(|e| e.as_str()) {
                let key = get_error_translation_key(first_error);
                return i18n.t(key);
            }
        }
    }

    // Fallback to direct message mapping
    let key = get_error_translation_key(response_text);
    i18n.t(key)
}

#[component]
#[allow(non_snake_case)]
#[allow(unused_variables)] // Placeholder implementation - variables will be used when auth is fully
                           // implemented
pub fn AuthProvider(children: leptos::prelude::Children) -> impl IntoView {
    let _i18n = use_i18n();
    let (state, set_state) = signal(AuthState::default());
    let (_access_token, set_access_token) = signal::<Option<String>>(None);
    let (_refresh_token_state, set_refresh_token) = signal::<Option<String>>(None);

    // Initialize auth state from localStorage - only in browser
    #[cfg(target_arch = "wasm32")]
    Effect::new(move |_| {
        if let Some(window) = web_sys::window() {
            if let Ok(Some(storage)) = window.local_storage() {
                // Load access token
                if let Ok(Some(token)) = storage.get_item("access_token") {
                    set_access_token.set(Some(token));
                }

                // Load refresh token
                if let Ok(Some(token)) = storage.get_item("refresh_token") {
                    set_refresh_token.set(Some(token));
                }

                // Load user data
                if let Ok(Some(user_data)) = storage.get_item("user") {
                    if let Ok(user) = serde_json::from_str::<User>(&user_data) {
                        set_state.update(|s| {
                            s.user = Some(user);
                        });
                    }
                }
            }
        }
    });

    // TODO: Implement actual login functionality
    #[allow(unused_variables)]
    let login_action = Arc::new(
        move |_email: String, _password: String, _remember_me: bool| {
            tracing::debug!("Login action called - not yet implemented");
        },
    );

    // TODO: Implement actual logout functionality
    #[allow(unused_variables)]
    let logout_action = Arc::new(move || {
        tracing::debug!("Logout action called - not yet implemented");
    });

    // TODO: Implement actual register functionality
    #[allow(unused_variables)]
    let register_action = Arc::new(
        move |_email: String,
              _password: String,
              _username: String,
              _display_name: Option<String>| {
            tracing::debug!("Register action called - not yet implemented");
        },
    );

    // TODO: Implement actual refresh token functionality
    #[allow(unused_variables)]
    let refresh_token_action = Arc::new(move || {
        tracing::debug!("Refresh token action called - not yet implemented");
    });

    // TODO: Implement actual update profile functionality
    #[allow(unused_variables)]
    let update_profile_action = Arc::new(
        move |_display_name: String, _first_name: Option<String>, _last_name: Option<String>| {
            tracing::debug!("Update profile action called - not yet implemented");
        },
    );

    // TODO: Implement actual change password functionality
    #[allow(unused_variables)]
    let change_password_action =
        Arc::new(move |_current_password: String, _new_password: String| {
            tracing::debug!("Change password action called - not yet implemented");
        });

    // TODO: Implement actual 2FA login functionality
    #[allow(unused_variables)]
    let login_with_2fa_action =
        Arc::new(move |_email: String, _code: String, _remember_me: bool| {
            tracing::debug!("Login with 2FA action called - not yet implemented");
        });

    // TODO: Implement actual 2FA reset functionality
    #[allow(unused_variables)]
    let reset_2fa_action = Arc::new(move || {
        tracing::debug!("Reset 2FA action called - not yet implemented");
    });

    // TODO: Implement actual logout functionality
    #[allow(unused_variables)]
    let logout_action = Arc::new(move || {
        tracing::debug!("Logout action called - not yet implemented");
    });

    // TODO: Implement actual register functionality
    #[allow(unused_variables)]
    let register_action = Arc::new(
        move |_email: String,
              _password: String,
              _username: String,
              _display_name: Option<String>| {
            tracing::debug!("Register action called - not yet implemented");
        },
    );

    // TODO: Implement actual refresh token functionality
    #[allow(unused_variables)]
    let refresh_token_action = Arc::new(move || {
        tracing::debug!("Refresh token action called - not yet implemented");
    });

    // TODO: Implement actual update profile functionality
    #[allow(unused_variables)]
    let update_profile_action = Arc::new(
        move |_display_name: String, _first_name: Option<String>, _last_name: Option<String>| {
            tracing::debug!("Update profile action called - not yet implemented");
        },
    );

    // TODO: Implement actual change password functionality
    #[allow(unused_variables)]
    let change_password_action =
        Arc::new(move |_current_password: String, _new_password: String| {
            tracing::debug!("Change password action called - not yet implemented");
        });

    // TODO: Implement actual clear error functionality
    #[allow(unused_variables)]
    let clear_error_action = Arc::new(move || {
        tracing::debug!("Clear error action called - not yet implemented");
    });

    // TODO: Implement actual 2FA login functionality
    #[allow(unused_variables)]
    let login_with_2fa_action =
        Arc::new(move |_email: String, _code: String, _remember_me: bool| {
            tracing::debug!("Login with 2FA action called - not yet implemented");
        });

    // TODO: Implement actual clear 2FA state functionality
    #[allow(unused_variables)]
    let clear_2fa_state_action = Arc::new(move || {
        tracing::debug!("Clear 2FA state action called - not yet implemented");
    });

    let actions = AuthActions {
        login: login_action,
        login_with_2fa: login_with_2fa_action,
        logout: logout_action,
        register: register_action,
        refresh_token: refresh_token_action,
        update_profile: update_profile_action,
        change_password: change_password_action,
        clear_error: clear_error_action,
        clear_2fa_state: clear_2fa_state_action,
    };

    let context = AuthContext { state, actions };

    provide_context(context);

    view! {
      {children()}
    }
}

#[derive(Clone)]
pub struct UseAuth(pub AuthContext);

impl Default for UseAuth {
    fn default() -> Self {
        Self::new()
    }
}

impl UseAuth {
    pub fn new() -> Self {
        Self(expect_context::<AuthContext>())
    }
}

pub fn use_auth() -> UseAuth {
    UseAuth::new()
}
