//! Session management using tower-sessions.

use sqlx::PgPool;
use tower_sessions::{Expiry, SessionManagerLayer, cookie::SameSite, cookie::time::Duration};
use tower_sessions_sqlx_store::PostgresStore;

/// Session cookie name.
pub const SESSION_COOKIE_NAME: &str = "chattyness_session";

/// Session user ID key.
pub const SESSION_USER_ID_KEY: &str = "user_id";

/// Session login type key (staff or realm).
pub const SESSION_LOGIN_TYPE_KEY: &str = "login_type";

/// Session current realm ID key (for realm logins).
pub const SESSION_CURRENT_REALM_KEY: &str = "current_realm_id";

/// Session original destination key (for password reset redirect).
pub const SESSION_ORIGINAL_DEST_KEY: &str = "original_destination";

/// Session guest ID key (for guest sessions).
pub const SESSION_GUEST_ID_KEY: &str = "guest_id";

/// Create the session management layer.
pub async fn create_session_layer(
    pool: PgPool,
    secure: bool,
) -> SessionManagerLayer<PostgresStore> {
    let session_store = PostgresStore::new(pool)
        .with_schema_name("auth")
        .expect("Invalid schema name for session store")
        .with_table_name("tower_sessions")
        .expect("Invalid table name for session store");

    SessionManagerLayer::new(session_store)
        .with_name(SESSION_COOKIE_NAME)
        .with_secure(secure)
        .with_same_site(SameSite::Lax)
        .with_http_only(true)
        .with_expiry(Expiry::OnInactivity(Duration::days(7)))
}

/// Hash a session token for storage.
pub fn hash_token(token: &str) -> String {
    use sha2::{Digest, Sha256};
    let mut hasher = Sha256::new();
    hasher.update(token.as_bytes());
    hex::encode(hasher.finalize())
}

/// Generate a random session token.
pub fn generate_token() -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let bytes: [u8; 32] = rng.r#gen();
    hex::encode(bytes)
}
