//! Authentication trait definitions
//!
//! This module defines the core traits that enable flexible authentication strategies.

use async_trait::async_trait;
use crate::{error::AuthResult, models::{AuthUser, Session}};

/// Port: Authentication provider
///
/// Implement this trait to add new authentication methods (database, LDAP, OAuth, etc.)
///
/// ## Example
///
/// ```rust
/// use lmrc_auth::{AuthProvider, AuthUser, Session, AuthResult};
/// use async_trait::async_trait;
///
/// struct CustomAuthProvider {
///     // Your implementation details
/// }
///
/// #[async_trait]
/// impl AuthProvider for CustomAuthProvider {
///     async fn authenticate(&self, email: &str, password: &str) -> AuthResult<AuthUser> {
///         // Your authentication logic
///         todo!()
///     }
///
///     async fn create_session(&self, user_id: i64) -> AuthResult<Session> {
///         // Your session creation logic
///         todo!()
///     }
///
///     async fn validate_session(&self, token: &str) -> AuthResult<Option<AuthUser>> {
///         // Your session validation logic
///         todo!()
///     }
///
///     async fn destroy_session(&self, token: &str) -> AuthResult<()> {
///         // Your session destruction logic
///         todo!()
///     }
///
///     async fn get_user(&self, user_id: i64) -> AuthResult<Option<AuthUser>> {
///         // Your user lookup logic
///         todo!()
///     }
/// }
/// ```
#[async_trait]
pub trait AuthProvider: Send + Sync {
    /// Authenticate user with credentials
    ///
    /// Returns the authenticated user if credentials are valid.
    async fn authenticate(&self, email: &str, password: &str) -> AuthResult<AuthUser>;

    /// Create a new session for authenticated user
    ///
    /// Generates a session token and stores the session.
    async fn create_session(&self, user_id: i64) -> AuthResult<Session>;

    /// Validate session token and return user
    ///
    /// Returns `None` if the session is invalid or expired.
    async fn validate_session(&self, token: &str) -> AuthResult<Option<AuthUser>>;

    /// Destroy session (logout)
    ///
    /// Removes the session from storage.
    async fn destroy_session(&self, token: &str) -> AuthResult<()>;

    /// Get user by ID
    ///
    /// Returns `None` if the user doesn't exist.
    async fn get_user(&self, user_id: i64) -> AuthResult<Option<AuthUser>>;
}

/// Port: Session storage
///
/// Implement this trait to use different session backends (database, Redis, in-memory, etc.)
///
/// ## Example
///
/// ```rust
/// use lmrc_auth::{SessionStore, Session, AuthResult};
/// use async_trait::async_trait;
///
/// struct RedisSessionStore {
///     // Redis connection pool
/// }
///
/// #[async_trait]
/// impl SessionStore for RedisSessionStore {
///     async fn store(&self, session: &Session) -> AuthResult<()> {
///         // Store in Redis
///         todo!()
///     }
///
///     async fn get(&self, token: &str) -> AuthResult<Option<Session>> {
///         // Retrieve from Redis
///         todo!()
///     }
///
///     async fn delete(&self, token: &str) -> AuthResult<()> {
///         // Delete from Redis
///         todo!()
///     }
///
///     async fn cleanup_expired(&self) -> AuthResult<usize> {
///         // Clean up expired sessions
///         todo!()
///     }
/// }
/// ```
#[async_trait]
pub trait SessionStore: Send + Sync {
    /// Store a session
    ///
    /// Persists the session to the backing storage.
    async fn store(&self, session: &Session) -> AuthResult<()>;

    /// Retrieve a session by token
    ///
    /// Returns `None` if the session doesn't exist.
    async fn get(&self, token: &str) -> AuthResult<Option<Session>>;

    /// Delete a session
    ///
    /// Removes the session from storage.
    async fn delete(&self, token: &str) -> AuthResult<()>;

    /// Clean up expired sessions
    ///
    /// Returns the number of sessions deleted.
    async fn cleanup_expired(&self) -> AuthResult<usize>;
}
