//! Guest session database queries.

use chrono::{DateTime, TimeDelta, Utc};
use sqlx::PgPool;
use uuid::Uuid;

use chattyness_error::AppError;

/// Guest session record.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
pub struct GuestSession {
    pub id: Uuid,
    pub guest_name: String,
    pub current_realm_id: Option<Uuid>,
    pub expires_at: DateTime<Utc>,
    pub created_at: DateTime<Utc>,
}

/// Create a new guest session.
///
/// Returns the guest session ID.
pub async fn create_guest_session(
    pool: &PgPool,
    guest_name: &str,
    realm_id: Uuid,
    token_hash: &str,
    user_agent: Option<&str>,
    ip_address: Option<&str>,
    expires_at: DateTime<Utc>,
) -> Result<Uuid, AppError> {
    let (session_id,): (Uuid,) = sqlx::query_as(
        r#"
        INSERT INTO auth.guest_sessions (guest_name, token_hash, user_agent, ip_address, current_realm_id, expires_at)
        VALUES ($1, $2, $3, $4::inet, $5, $6)
        RETURNING id
        "#,
    )
    .bind(guest_name)
    .bind(token_hash)
    .bind(user_agent)
    .bind(ip_address)
    .bind(realm_id)
    .bind(expires_at)
    .fetch_one(pool)
    .await?;

    Ok(session_id)
}

/// Get a guest session by ID.
pub async fn get_guest_session(pool: &PgPool, session_id: Uuid) -> Result<Option<GuestSession>, AppError> {
    let session = sqlx::query_as::<_, GuestSession>(
        r#"
        SELECT id, guest_name, current_realm_id, expires_at, created_at
        FROM auth.guest_sessions
        WHERE id = $1 AND expires_at > now()
        "#,
    )
    .bind(session_id)
    .fetch_optional(pool)
    .await?;

    // Update last activity if session exists
    if session.is_some() {
        sqlx::query("UPDATE auth.guest_sessions SET last_activity_at = now() WHERE id = $1")
            .bind(session_id)
            .execute(pool)
            .await?;
    }

    Ok(session)
}

/// Delete a guest session.
pub async fn delete_guest_session(pool: &PgPool, session_id: Uuid) -> Result<(), AppError> {
    sqlx::query("DELETE FROM auth.guest_sessions WHERE id = $1")
        .bind(session_id)
        .execute(pool)
        .await?;
    Ok(())
}

/// Generate a random guest name like "Guest_12345".
pub fn generate_guest_name() -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let number: u32 = rng.gen_range(10000..100000);
    format!("Guest_{}", number)
}

/// Calculate guest session expiry (24 hours from now).
pub fn guest_session_expiry() -> DateTime<Utc> {
    Utc::now() + TimeDelta::hours(24)
}
