//! Support code database operations

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use uuid::Uuid;

/// Support code record from database
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
pub struct DbSupportCode {
    pub id: Uuid,
    pub code: String,
    pub session_id: Option<Uuid>,
    pub created_by: String,
    pub created_at: DateTime<Utc>,
    pub expires_at: Option<DateTime<Utc>>,
    pub status: String,
    pub client_name: Option<String>,
    pub client_machine: Option<String>,
    pub connected_at: Option<DateTime<Utc>>,
}

/// Create a new support code
pub async fn create_support_code(
    pool: &PgPool,
    code: &str,
    created_by: &str,
) -> Result<DbSupportCode, sqlx::Error> {
    sqlx::query_as::<_, DbSupportCode>(
        r#"
        INSERT INTO connect_support_codes (code, created_by, status)
        VALUES ($1, $2, 'pending')
        RETURNING *
        "#,
    )
    .bind(code)
    .bind(created_by)
    .fetch_one(pool)
    .await
}

/// Get support code by code string
pub async fn get_support_code(pool: &PgPool, code: &str) -> Result<Option<DbSupportCode>, sqlx::Error> {
    sqlx::query_as::<_, DbSupportCode>(
        "SELECT * FROM connect_support_codes WHERE code = $1"
    )
    .bind(code)
    .fetch_optional(pool)
    .await
}

/// Update support code when client connects
pub async fn mark_code_connected(
    pool: &PgPool,
    code: &str,
    session_id: Option<Uuid>,
    client_name: Option<&str>,
    client_machine: Option<&str>,
) -> Result<(), sqlx::Error> {
    sqlx::query(
        r#"
        UPDATE connect_support_codes SET
            status = 'connected',
            session_id = $1,
            client_name = $2,
            client_machine = $3,
            connected_at = NOW()
        WHERE code = $4
        "#,
    )
    .bind(session_id)
    .bind(client_name)
    .bind(client_machine)
    .bind(code)
    .execute(pool)
    .await?;
    Ok(())
}

/// Mark support code as completed
pub async fn mark_code_completed(pool: &PgPool, code: &str) -> Result<(), sqlx::Error> {
    sqlx::query("UPDATE connect_support_codes SET status = 'completed' WHERE code = $1")
        .bind(code)
        .execute(pool)
        .await?;
    Ok(())
}

/// Mark support code as cancelled
pub async fn mark_code_cancelled(pool: &PgPool, code: &str) -> Result<(), sqlx::Error> {
    sqlx::query("UPDATE connect_support_codes SET status = 'cancelled' WHERE code = $1")
        .bind(code)
        .execute(pool)
        .await?;
    Ok(())
}

/// Get active support codes (pending or connected)
pub async fn get_active_support_codes(pool: &PgPool) -> Result<Vec<DbSupportCode>, sqlx::Error> {
    sqlx::query_as::<_, DbSupportCode>(
        "SELECT * FROM connect_support_codes WHERE status IN ('pending', 'connected') ORDER BY created_at DESC"
    )
    .fetch_all(pool)
    .await
}

/// Check if code exists and is valid for connection
pub async fn is_code_valid(pool: &PgPool, code: &str) -> Result<bool, sqlx::Error> {
    let result = sqlx::query_scalar::<_, bool>(
        "SELECT EXISTS(SELECT 1 FROM connect_support_codes WHERE code = $1 AND status = 'pending')"
    )
    .bind(code)
    .fetch_one(pool)
    .await?;
    Ok(result)
}

/// Check if code is cancelled
pub async fn is_code_cancelled(pool: &PgPool, code: &str) -> Result<bool, sqlx::Error> {
    let result = sqlx::query_scalar::<_, bool>(
        "SELECT EXISTS(SELECT 1 FROM connect_support_codes WHERE code = $1 AND status = 'cancelled')"
    )
    .bind(code)
    .fetch_one(pool)
    .await?;
    Ok(result)
}

/// Link session to support code
pub async fn link_session_to_code(
    pool: &PgPool,
    code: &str,
    session_id: Uuid,
) -> Result<(), sqlx::Error> {
    sqlx::query("UPDATE connect_support_codes SET session_id = $1 WHERE code = $2")
        .bind(session_id)
        .bind(code)
        .execute(pool)
        .await?;
    Ok(())
}
