/// Serializable result of a successful OTP verification — available on both
/// SSR and WASM so Leptos server functions can return it directly.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum OtpVerifyResult {
    /// The email belongs to an existing account; session is ready.
    Authenticated {
        user: rustelo_core_lib::state::UserInfo,
        session_token: String,
    },
    /// The email is new; GDPR consent must be obtained before account creation.
    NeedsConsent { pending_token: String },
}

/// OTP service facade for use from Leptos server functions.
///
/// Defined in `rustelo_components_leptos` so the UI auth components can call
/// OTP operations without a direct dependency on `rustelo_server`.  The
/// concrete implementation lives in `rustelo_server` and is registered as an
/// Axum `Extension` at startup.
#[cfg(feature = "ssr")]
pub mod server {
    use std::future::Future;
    use std::pin::Pin;
    use std::sync::Arc;

    use super::OtpVerifyResult;

    pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;

    use crate::auth::server_fns::{
        BookmarkInfo, CreatedServiceToken, ServiceTokenInfo, UserMessage, UserNote, UserResource,
    };

    /// Abstraction over the OTP backend, injected by the consumer at startup.
    pub trait OtpServiceFacade: Send + Sync {
        fn request_otp(&self, email: &str, lang: &str) -> BoxFuture<Result<(), String>>;
        fn verify_otp(&self, email: &str, code: &str)
            -> BoxFuture<Result<OtpVerifyResult, String>>;
        fn accept_gdpr(&self, pending_token: &str) -> BoxFuture<Result<OtpVerifyResult, String>>;
        fn logout_session(&self, session_token: &str) -> BoxFuture<Result<(), String>>;
        fn get_bookmarks(
            &self,
            session_token: &str,
        ) -> BoxFuture<Result<Vec<BookmarkInfo>, String>>;
        fn add_bookmark(
            &self,
            session_token: &str,
            content_type: String,
            content_id: String,
            content_title: Option<String>,
            content_url: Option<String>,
        ) -> BoxFuture<Result<String, String>>;
        fn remove_bookmark(
            &self,
            session_token: &str,
            bookmark_id: String,
        ) -> BoxFuture<Result<(), String>>;
        fn is_bookmarked(
            &self,
            session_token: &str,
            content_id: String,
            content_type: String,
        ) -> BoxFuture<Result<bool, String>>;
        fn delete_account(&self, session_token: &str) -> BoxFuture<Result<(), String>>;
        fn update_display_name(
            &self,
            session_token: &str,
            name: String,
        ) -> BoxFuture<Result<(), String>>;

        /// Rotate the session: verify the existing access token, issue a fresh
        /// one, and return the new raw JWT string so the caller can set
        /// a new cookie.
        fn refresh_session(&self, session_token: &str) -> BoxFuture<Result<String, String>>;

        /// Invalidate all active sessions for the user identified by
        /// `session_token`.
        fn logout_all_sessions(&self, session_token: &str) -> BoxFuture<Result<(), String>>;

        /// Resolve a session token to the owning user UUID without a DB
        /// round-trip.
        fn get_user_id_from_token(
            &self,
            session_token: &str,
        ) -> BoxFuture<Result<uuid::Uuid, String>>;

        /// Resolve a valid session token to the full `UserInfo` record.
        ///
        /// Validates the JWT and performs one DB lookup to fetch display name
        /// and avatar.  Returns `Err` if the token is invalid or the user no
        /// longer exists.  Used by the WASM session-restoration path that runs
        /// on every new tab open.
        fn get_session_user(
            &self,
            session_token: &str,
        ) -> BoxFuture<Result<rustelo_core_lib::state::UserInfo, String>>;

        fn get_messages(&self, session_token: &str) -> BoxFuture<Result<Vec<UserMessage>, String>>;

        fn mark_message_read(
            &self,
            session_token: &str,
            message_id: String,
        ) -> BoxFuture<Result<(), String>>;

        fn get_notes(&self, session_token: &str) -> BoxFuture<Result<Vec<UserNote>, String>>;

        fn create_note(
            &self,
            session_token: &str,
            title: String,
            content: String,
        ) -> BoxFuture<Result<String, String>>;

        fn update_note(
            &self,
            session_token: &str,
            note_id: String,
            title: String,
            content: String,
        ) -> BoxFuture<Result<(), String>>;

        fn delete_note(
            &self,
            session_token: &str,
            note_id: String,
        ) -> BoxFuture<Result<(), String>>;

        fn get_resources(
            &self,
            session_token: &str,
        ) -> BoxFuture<Result<Vec<UserResource>, String>>;

        // ── Service token management (admin only) ─────────────────────────────

        fn delete_message(
            &self,
            session_token: &str,
            message_id: String,
        ) -> BoxFuture<Result<(), String>>;

        fn list_service_tokens(
            &self,
            session_token: &str,
        ) -> BoxFuture<Result<Vec<ServiceTokenInfo>, String>>;

        fn create_service_token(
            &self,
            session_token: &str,
            name: String,
            scopes: Vec<String>,
            expires_days: Option<u32>,
        ) -> BoxFuture<Result<CreatedServiceToken, String>>;

        fn revoke_service_token(
            &self,
            session_token: &str,
            token_id: String,
        ) -> BoxFuture<Result<(), String>>;

        // ── Activity completions ───────────────────────────────────────────

        /// Return `true` if the authenticated user already completed the
        /// questionnaire for `activity_id`.
        fn check_activity_completion(
            &self,
            session_token: &str,
            activity_id: String,
        ) -> BoxFuture<Result<bool, String>>;

        /// Record that the authenticated user completed the questionnaire.
        fn record_activity_completion(
            &self,
            session_token: &str,
            activity_id: String,
            questionnaire_type: String,
        ) -> BoxFuture<Result<(), String>>;

        /// Submit responses for an internal questionnaire and record
        /// completion.
        fn submit_internal_questionnaire(
            &self,
            session_token: &str,
            activity_id: String,
            responses: Vec<(String, String)>,
        ) -> BoxFuture<Result<(), String>>;

        /// Record completion using a raw user UUID string (from HMAC callback).
        ///
        /// Used by the Axum callback endpoint where the identity is proven by
        /// a signed token rather than a live session cookie.
        fn record_activity_completion_by_user_id(
            &self,
            user_id: &str,
            activity_id: String,
            questionnaire_type: &str,
        ) -> BoxFuture<Result<(), String>>;
    }

    /// Axum `Extension` wrapper so
    /// `extract::<Extension<OtpServiceExtension>>()` works inside
    /// `#[server]` functions.
    #[derive(Clone)]
    pub struct OtpServiceExtension(pub Arc<dyn OtpServiceFacade>);
}
