use crate::i18n::UseI18n;
use serde_json;
use shared::auth::AuthError;

/// Helper struct for handling authentication errors with internationalization
#[derive(Clone)]
pub struct AuthErrorHandler {
    i18n: UseI18n,
}

impl AuthErrorHandler {
    pub fn new(i18n: UseI18n) -> Self {
        Self { i18n }
    }

    /// Convert a server response error to a localized error message
    pub async fn handle_response_error(&self, response: &reqwasm::http::Response) -> String {
        if let Ok(error_text) = response.text().await {
            self.map_error_to_localized_message(&error_text)
        } else {
            self.i18n.t("unknown-error")
        }
    }

    /// Map error text to localized message
    pub fn map_error_to_localized_message(&self, error_text: &str) -> String {
        let translation_key = self.map_error_to_translation_key(error_text);
        self.i18n.t(&translation_key)
    }

    /// Map server errors to translation keys
    pub fn map_error_to_translation_key(&self, error_text: &str) -> String {
        // Try to parse as JSON first (standard API error response)
        if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(error_text) {
            if let Some(message) = json_value.get("message").and_then(|m| m.as_str()) {
                return self.map_error_message_to_key(message);
            }
            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()) {
                    return self.map_error_message_to_key(first_error);
                }
            }
        }

        // Fallback to direct message mapping
        self.map_error_message_to_key(error_text)
    }

    /// Map error messages to translation keys
    fn map_error_message_to_key(&self, message: &str) -> String {
        let message_lower = message.to_lowercase();

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

    /// Handle AuthError enum directly
    pub fn handle_auth_error(&self, error: &AuthError) -> String {
        let translation_key = match error {
            AuthError::InvalidCredentials => "invalid-credentials",
            AuthError::UserNotFound => "user-not-found",
            AuthError::EmailAlreadyExists => "email-already-exists",
            AuthError::UsernameAlreadyExists => "username-already-exists",
            AuthError::InvalidToken => "invalid-token",
            AuthError::TokenExpired => "token-expired",
            AuthError::InsufficientPermissions => "insufficient-permissions",
            AuthError::AccountNotVerified => "account-not-verified",
            AuthError::AccountSuspended => "account-suspended",
            AuthError::RateLimitExceeded => "rate-limit-exceeded",
            AuthError::OAuthError(_) => "oauth-error",
            AuthError::DatabaseError => "database-error",
            AuthError::InternalError => "internal-error",
            AuthError::ValidationError(_) => "validation-error",
        };

        self.i18n.t(translation_key)
    }

    /// Handle network errors
    pub fn handle_network_error(&self) -> String {
        self.i18n.t("network-error")
    }

    /// Handle generic request failures
    pub fn handle_request_failure(&self, operation: &str) -> String {
        match operation {
            "login" => self.i18n.t("login-failed"),
            "register" => self.i18n.t("registration-failed"),
            "profile-update" => self.i18n.t("profile-update-failed"),
            "password-change" => self.i18n.t("password-change-failed"),
            _ => self.i18n.t("request-failed"),
        }
    }

    /// Check if an error indicates session expiration
    pub fn is_session_expired(&self, error_text: &str) -> bool {
        let error_lower = error_text.to_lowercase();
        error_lower.contains("session expired")
            || error_lower.contains("token expired")
            || error_lower.contains("invalid token")
            || error_lower.contains("unauthorized")
    }

    /// Get appropriate error message for session expiration
    pub fn get_session_expired_message(&self) -> String {
        self.i18n.t("session-expired")
    }
}

/// Helper function to create an AuthErrorHandler
pub fn create_auth_error_handler(i18n: UseI18n) -> AuthErrorHandler {
    AuthErrorHandler::new(i18n)
}

/// Trait for handling authentication errors consistently
pub trait AuthErrorHandling {
    fn handle_auth_error(&self, error: &str) -> String;
    fn handle_network_error(&self) -> String;
    fn handle_session_expired(&self) -> String;
}

impl AuthErrorHandling for UseI18n {
    fn handle_auth_error(&self, error: &str) -> String {
        let handler = create_auth_error_handler(self.clone());
        handler.map_error_to_localized_message(error)
    }

    fn handle_network_error(&self) -> String {
        self.t("network-error")
    }

    fn handle_session_expired(&self) -> String {
        self.t("session-expired")
    }
}
