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

use crate::auth::{ProfileType as AuthProfileType, UserContext};
use crate::db::Database;
use crate::graphql::types::{CustomerInfo, CustomerProfileType, ProfileType, TeamProfileType};
use crate::models::{CustomerProfile, EntityStatus, TeamProfile};

#[derive(Default)]
pub struct ProfileQuery;

#[Object]
impl ProfileQuery {
    /// Get all non-inactive team profiles
    async fn team_profiles(&self, ctx: &Context<'_>) -> Result<Vec<TeamProfileType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Exclude only explicitly inactive profiles - includes ACTIVE, PENDING, and any other status
        let profiles = sqlx::query_as::<_, TeamProfile>(
            r#"
            SELECT id, created_at, updated_at, first_name, last_name, phone, email, role, status, notes
            FROM team_profiles
            WHERE status != $1
            ORDER BY first_name, last_name
            "#,
        )
        .bind(EntityStatus::Inactive)
        .fetch_all(&*pool)
        .await?;

        Ok(profiles.into_iter().map(TeamProfileType::from).collect())
    }

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

        let profile = sqlx::query_as::<_, TeamProfile>(
            r#"
            SELECT id, created_at, updated_at, first_name, last_name, phone, email, role, status, notes
            FROM team_profiles
            WHERE id = $1
            "#,
        )
        .bind(id)
        .fetch_optional(&*pool)
        .await?
        .ok_or_else(|| async_graphql::Error::new("Team profile not found"))?;

        Ok(TeamProfileType::from(profile))
    }

    /// Get all non-inactive customer profiles
    async fn customer_profiles(&self, ctx: &Context<'_>) -> Result<Vec<CustomerProfileType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let profiles = sqlx::query_as::<_, CustomerProfile>(
            r#"
            SELECT id, created_at, updated_at, first_name, last_name, phone, email, status, notes
            FROM customer_profiles
            WHERE status != $1
            ORDER BY first_name, last_name
            "#,
        )
        .bind(EntityStatus::Inactive)
        .fetch_all(&*pool)
        .await?;

        Ok(profiles.into_iter().map(CustomerProfileType::from).collect())
    }

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

        let profile = sqlx::query_as::<_, CustomerProfile>(
            r#"
            SELECT id, created_at, updated_at, first_name, last_name, phone, email, status, notes
            FROM customer_profiles
            WHERE id = $1
            "#,
        )
        .bind(id)
        .fetch_optional(&*pool)
        .await?
        .ok_or_else(|| async_graphql::Error::new("Customer profile not found"))?;

        // Fetch associated customers
        let customers = sqlx::query_as::<_, (Uuid, String)>(
            r#"
            SELECT c.id, c.name
            FROM customers c
            INNER JOIN customer_profile_access cpa ON cpa.customer_id = c.id
            WHERE cpa.customer_profile_id = $1
            "#,
        )
        .bind(id)
        .fetch_all(&*pool)
        .await?
        .into_iter()
        .map(|(id, name)| CustomerInfo { id, name })
        .collect();

        Ok(CustomerProfileType::from_profile(profile, customers))
    }

    /// Get the currently authenticated user's profile
    async fn me(&self, ctx: &Context<'_>) -> Result<Option<ProfileType>> {
        // Get user context from GraphQL context
        let user_ctx = match ctx.data_opt::<UserContext>() {
            Some(ctx) => ctx,
            None => return Ok(None), // Not authenticated
        };

        // Get database from GraphQL context
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        match user_ctx.profile_type {
            AuthProfileType::Team => {
                let profile = sqlx::query_as::<_, TeamProfile>(
                    r#"
                    SELECT id, created_at, updated_at, first_name, last_name, phone, email, role, status, notes
                    FROM team_profiles
                    WHERE id = $1
                    "#,
                )
                .bind(user_ctx.user_id)
                .fetch_optional(&*pool)
                .await?;

                Ok(profile.map(|p| ProfileType::TeamProfile(p.into())))
            }
            AuthProfileType::Customer => {
                let profile = sqlx::query_as::<_, CustomerProfile>(
                    r#"
                    SELECT id, created_at, updated_at, first_name, last_name, phone, email, status, notes
                    FROM customer_profiles
                    WHERE id = $1
                    "#,
                )
                .bind(user_ctx.user_id)
                .fetch_optional(&*pool)
                .await?;

                match profile {
                    Some(p) => {
                        // Fetch associated customers
                        let customers = sqlx::query_as::<_, (uuid::Uuid, String)>(
                            r#"
                            SELECT c.id, c.name
                            FROM customers c
                            INNER JOIN customer_profile_access cpa ON cpa.customer_id = c.id
                            WHERE cpa.customer_profile_id = $1
                            "#,
                        )
                        .bind(user_ctx.user_id)
                        .fetch_all(&*pool)
                        .await?
                        .into_iter()
                        .map(|(id, name)| CustomerInfo { id, name })
                        .collect();

                        Ok(Some(ProfileType::CustomerProfile(
                            CustomerProfileType::from_profile(p, customers),
                        )))
                    }
                    None => Ok(None),
                }
            }
        }
    }
}
