use sqlx::{PgPool, FromRow};
use crate::error::{ApiError, Result};

/// Generic database query execution with error handling
pub struct QueryBuilder;

impl QueryBuilder {
    /// Execute a query and return a single row
    pub async fn fetch_one<T>(pool: &PgPool, query: &str) -> Result<T>
    where
        T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    {
        sqlx::query_as::<_, T>(query)
            .fetch_one(pool)
            .await
            .map_err(|e| match e {
                sqlx::Error::RowNotFound => ApiError::NotFound("Record not found".to_string()),
                _ => ApiError::DatabaseError(e),
            })
    }

    /// Execute a query and return multiple rows
    pub async fn fetch_all<T>(pool: &PgPool, query: &str) -> Result<Vec<T>>
    where
        T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    {
        sqlx::query_as::<_, T>(query)
            .fetch_all(pool)
            .await
            .map_err(ApiError::DatabaseError)
    }

    /// Execute a query and return an optional row
    pub async fn fetch_optional<T>(pool: &PgPool, query: &str) -> Result<Option<T>>
    where
        T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    {
        sqlx::query_as::<_, T>(query)
            .fetch_optional(pool)
            .await
            .map_err(ApiError::DatabaseError)
    }

    // Commented out due to lifetime issues - use direct sqlx::query_as! instead
    // /// Execute a parameterized query and return a single row
    // pub async fn fetch_one_with_params<T>(
    //     pool: &PgPool,
    //     query: &str,
    //     params: impl sqlx::IntoArguments<'_, sqlx::Postgres> + Send,
    // ) -> Result<T>
    // where
    //     T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    // {
    //     sqlx::query_as_with::<_, T, _>(query, params)
    //         .fetch_one(pool)
    //         .await
    //         .map_err(|e| match e {
    //             sqlx::Error::RowNotFound => ApiError::NotFound("Record not found".to_string()),
    //             _ => ApiError::DatabaseError(e),
    //         })
    // }

    // Commented out due to lifetime issues - use direct sqlx::query_as! instead
    // /// Execute a parameterized query and return multiple rows
    // pub async fn fetch_all_with_params<T>(
    //     pool: &PgPool,
    //     query: &str,
    //     params: impl sqlx::IntoArguments<'_, sqlx::Postgres> + Send,
    // ) -> Result<Vec<T>>
    // where
    //     T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    // {
    //     sqlx::query_as_with::<_, T, _>(query, params)
    //         .fetch_all(pool)
    //         .await
    //         .map_err(ApiError::DatabaseError)
    // }

    // Commented out due to lifetime issues - use direct sqlx::query_as! instead
    // /// Execute a parameterized query and return an optional row
    // pub async fn fetch_optional_with_params<T>(
    //     pool: &PgPool,
    //     query: &str,
    //     params: impl sqlx::IntoArguments<'_, sqlx::Postgres> + Send,
    // ) -> Result<Option<T>>
    // where
    //     T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin,
    // {
    //     sqlx::query_as_with::<_, T, _>(query, params)
    //         .fetch_optional(pool)
    //         .await
    //         .map_err(ApiError::DatabaseError)
    // }

    // Commented out due to lifetime issues - use direct sqlx::query! instead
    // /// Execute an INSERT/UPDATE/DELETE query
    // pub async fn execute(
    //     pool: &PgPool,
    //     query: &str,
    //     params: impl sqlx::IntoArguments<'_, sqlx::Postgres> + Send,
    // ) -> Result<u64> {
    //     sqlx::query_with(query, params)
    //         .execute(pool)
    //         .await
    //         .map(|result| result.rows_affected())
    //         .map_err(ApiError::DatabaseError)
    // }
}

