use async_graphql::{Context, Object, Result};
use uuid::Uuid;

use crate::db::Database;
use crate::graphql::types::{CustomerFilter, CustomerType};
use crate::models::{Customer, EntityStatus};

#[derive(Default)]
pub struct CustomerQuery;

#[Object]
impl CustomerQuery {
    /// Get all customers with optional filtering
    async fn customers(
        &self,
        ctx: &Context<'_>,
        filter: Option<CustomerFilter>,
    ) -> Result<Vec<CustomerType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let filter = filter.unwrap_or_default();

        // Build the query with optional filters
        let name_pattern = filter
            .name
            .as_ref()
            .map(|n| format!("%{}%", n.to_lowercase()));
        let status: Option<EntityStatus> = filter.status.map(|s| s.into());

        let customers: Vec<Customer> = sqlx::query_as::<_, Customer>(
            r#"
            SELECT id, created_at, updated_at, name, status, start_date, end_date,
                   billing_terms, billing_email, wave_customer_id
            FROM customers
            WHERE ($1::text IS NULL OR LOWER(name) LIKE $1)
              AND ($2::entity_status IS NULL OR status = $2)
            ORDER BY name ASC
            "#,
        )
        .bind(name_pattern)
        .bind(status)
        .fetch_all(&*pool)
        .await?;

        // Convert to GraphQL types and optionally filter by is_active (computed field)
        let mut results: Vec<CustomerType> = customers.into_iter().map(CustomerType::from).collect();

        if let Some(is_active) = filter.is_active {
            results.retain(|c| c.is_active == is_active);
        }

        Ok(results)
    }

    /// Get a single customer by ID
    async fn customer(&self, ctx: &Context<'_>, id: Uuid) -> Result<Option<CustomerType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let customer = sqlx::query_as::<_, Customer>(
            r#"
            SELECT id, created_at, updated_at, name, status, start_date, end_date,
                   billing_terms, billing_email, wave_customer_id
            FROM customers
            WHERE id = $1
            "#,
        )
        .bind(id)
        .fetch_optional(&*pool)
        .await?;

        Ok(customer.map(CustomerType::from))
    }
}
