use async_graphql::{Context, InputObject, Object, Result};
use chrono::NaiveDate;
use rust_decimal::Decimal;
use uuid::Uuid;

use crate::auth::UserContext;
use crate::db::Database;
use crate::graphql::types::{ProjectTeamMemberType, ProjectType, WorkStatusType};
use crate::models::{
    EventType, Project, ProjectScope, ProjectScopeCategory, ProjectScopeTask, ProjectTeamMember,
    WorkStatus,
};
use crate::services::{EventPublisher, JobQueue};

/// Input for creating a project
#[derive(InputObject)]
pub struct CreateProjectInput {
    pub customer_id: Uuid,
    pub name: String,
    pub date: NaiveDate,
    pub status: Option<WorkStatusType>,
    pub account_address_id: Option<Uuid>,
    pub street_address: Option<String>,
    pub city: Option<String>,
    pub state: Option<String>,
    pub zip_code: Option<String>,
}

/// Input for updating a project
#[derive(InputObject)]
pub struct UpdateProjectInput {
    pub name: Option<String>,
    pub date: Option<NaiveDate>,
    pub status: Option<WorkStatusType>,
    pub labor: Option<Decimal>,
    pub amount: Option<Decimal>,
    pub wave_service_id: Option<String>,
    pub notes: Option<String>,
    pub calendar_event_id: Option<String>,
    pub account_address_id: Option<Uuid>,
    pub street_address: Option<String>,
    pub city: Option<String>,
    pub state: Option<String>,
    pub zip_code: Option<String>,
}

/// Input for creating a project scope
#[derive(InputObject)]
pub struct CreateProjectScopeInput {
    pub name: String,
    pub description: Option<String>,
    pub categories: Option<Vec<CreateProjectCategoryInput>>,
}

/// Input for updating a project scope
#[derive(InputObject)]
pub struct UpdateProjectScopeInput {
    pub name: Option<String>,
    pub description: Option<String>,
    pub is_active: Option<bool>,
}

/// Input for creating a project scope task (no frequency - project tasks are one-time)
#[derive(InputObject)]
pub struct CreateProjectScopeTaskInput {
    pub scope_description: String,
    pub checklist_description: Option<String>,
    pub session_description: Option<String>,
    pub order: Option<i32>,
    pub estimated_minutes: Option<i32>,
}

/// Input for updating a project scope task (no frequency - project tasks are one-time)
#[derive(InputObject)]
pub struct UpdateProjectScopeTaskInput {
    pub scope_description: Option<String>,
    pub checklist_description: Option<String>,
    pub session_description: Option<String>,
    pub order: Option<i32>,
    pub estimated_minutes: Option<i32>,
}

/// Input for creating a project scope category
#[derive(InputObject)]
pub struct CreateProjectCategoryInput {
    pub name: String,
    pub order: Option<i32>,
    pub tasks: Option<Vec<CreateProjectScopeTaskInput>>,
}

/// Input for updating a project scope category
#[derive(InputObject)]
pub struct UpdateProjectCategoryInput {
    pub name: Option<String>,
    pub order: Option<i32>,
}

#[derive(Default)]
pub struct ProjectMutation;

/// Project scope GraphQL type
#[derive(async_graphql::SimpleObject)]
#[graphql(complex)]
pub struct ProjectScopeType {
    pub id: Uuid,
    pub name: String,
    pub description: Option<String>,
    pub is_active: bool,
}

#[async_graphql::ComplexObject]
impl ProjectScopeType {
    /// Get categories for this scope
    async fn categories(&self, ctx: &Context<'_>) -> Result<Vec<ProjectScopeCategoryType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let categories: Vec<ProjectScopeCategory> = sqlx::query_as::<_, ProjectScopeCategory>(
            r#"
            SELECT id, created_at, updated_at, scope_id, name, "order"
            FROM project_scope_categories
            WHERE scope_id = $1
            ORDER BY "order" ASC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(categories.into_iter().map(ProjectScopeCategoryType::from).collect())
    }
}

impl From<ProjectScope> for ProjectScopeType {
    fn from(scope: ProjectScope) -> Self {
        Self {
            id: scope.base.id,
            name: scope.name,
            description: scope.description,
            is_active: scope.is_active,
        }
    }
}

/// Project scope category GraphQL type
#[derive(async_graphql::SimpleObject)]
#[graphql(complex)]
pub struct ProjectScopeCategoryType {
    pub id: Uuid,
    pub name: String,
    pub order: i32,
}

#[async_graphql::ComplexObject]
impl ProjectScopeCategoryType {
    /// Get tasks for this category
    async fn tasks(&self, ctx: &Context<'_>) -> Result<Vec<ProjectScopeTaskType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let tasks: Vec<ProjectScopeTask> = sqlx::query_as::<_, ProjectScopeTask>(
            r#"
            SELECT id, created_at, updated_at, category_id, scope_description,
                   checklist_description, session_description, "order", estimated_minutes
            FROM project_scope_tasks
            WHERE category_id = $1
            ORDER BY "order" ASC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(tasks.into_iter().map(ProjectScopeTaskType::from).collect())
    }
}

impl From<ProjectScopeCategory> for ProjectScopeCategoryType {
    fn from(category: ProjectScopeCategory) -> Self {
        Self {
            id: category.base.id,
            name: category.name,
            order: category.order,
        }
    }
}

/// Project scope task GraphQL type
/// Note: Unlike service tasks, project tasks don't have frequency - they are one-time
#[derive(async_graphql::SimpleObject)]
pub struct ProjectScopeTaskType {
    pub id: Uuid,
    pub scope_description: String,
    pub checklist_description: String,
    pub session_description: String,
    pub order: i32,
    pub estimated_minutes: Option<i32>,
}

impl From<ProjectScopeTask> for ProjectScopeTaskType {
    fn from(task: ProjectScopeTask) -> Self {
        Self {
            id: task.base.id,
            scope_description: task.scope_description,
            checklist_description: task.checklist_description,
            session_description: task.session_description,
            order: task.order,
            estimated_minutes: task.estimated_minutes,
        }
    }
}

#[Object]
impl ProjectMutation {
    /// Create a new project
    async fn create_project(
        &self,
        ctx: &Context<'_>,
        input: CreateProjectInput,
    ) -> Result<ProjectType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let status = input.status.map(WorkStatus::from).unwrap_or(WorkStatus::Scheduled);

        let project: Project = sqlx::query_as::<_, Project>(
            r#"
            INSERT INTO projects (
                id, created_at, updated_at, customer_id, name, date, status,
                account_address_id, street_address, city, state, zip_code
            )
            VALUES (
                gen_random_uuid(), NOW(), NOW(), $1, $2, $3, $4, $5, $6, $7, $8, $9
            )
            RETURNING id, created_at, updated_at, customer_id, name, date, status, labor, amount,
                      notes, calendar_event_id, wave_service_id, account_address_id,
                      street_address, city, state, zip_code
            "#,
        )
        .bind(input.customer_id)
        .bind(&input.name)
        .bind(input.date)
        .bind(status)
        .bind(input.account_address_id)
        .bind(&input.street_address)
        .bind(&input.city)
        .bind(&input.state)
        .bind(&input.zip_code)
        .fetch_one(&*pool)
        .await?;

        // Publish ProjectCreated event
        if let (Ok(user), Ok(job_queue)) = (ctx.data::<UserContext>(), ctx.data::<JobQueue>()) {
            let _ = EventPublisher::publish_and_queue(
                &pool,
                job_queue,
                EventType::ProjectCreated,
                "project",
                project.base.id,
                Some(("team_profile", user.user_id)),
                None,
            )
            .await;
        }

        Ok(ProjectType::from(project))
    }

    /// Update a project
    async fn update_project(
        &self,
        ctx: &Context<'_>,
        id: Uuid,
        input: UpdateProjectInput,
    ) -> Result<ProjectType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get old status for event tracking
        let old_status: Option<WorkStatus> = sqlx::query_scalar(
            "SELECT status FROM projects WHERE id = $1",
        )
        .bind(id)
        .fetch_optional(&*pool)
        .await?;

        let new_status = input.status.map(WorkStatus::from);

        let project: Project = sqlx::query_as::<_, Project>(
            r#"
            UPDATE projects
            SET
                name = COALESCE($2, name),
                date = COALESCE($3, date),
                status = COALESCE($4, status),
                labor = COALESCE($5, labor),
                amount = COALESCE($6, amount),
                wave_service_id = COALESCE($7, wave_service_id),
                notes = COALESCE($8, notes),
                calendar_event_id = COALESCE($9, calendar_event_id),
                account_address_id = COALESCE($10, account_address_id),
                street_address = COALESCE($11, street_address),
                city = COALESCE($12, city),
                state = COALESCE($13, state),
                zip_code = COALESCE($14, zip_code),
                updated_at = NOW()
            WHERE id = $1
            RETURNING id, created_at, updated_at, customer_id, name, date, status, labor, amount,
                      notes, calendar_event_id, wave_service_id, account_address_id,
                      street_address, city, state, zip_code
            "#,
        )
        .bind(id)
        .bind(&input.name)
        .bind(input.date)
        .bind(new_status)
        .bind(input.labor)
        .bind(input.amount)
        .bind(&input.wave_service_id)
        .bind(&input.notes)
        .bind(&input.calendar_event_id)
        .bind(input.account_address_id)
        .bind(&input.street_address)
        .bind(&input.city)
        .bind(&input.state)
        .bind(&input.zip_code)
        .fetch_one(&*pool)
        .await?;

        // Publish event for status change
        if let (Ok(user), Ok(job_queue)) = (ctx.data::<UserContext>(), ctx.data::<JobQueue>()) {
            if let (Some(old), Some(new)) = (old_status, new_status) {
                if old != new {
                    let _ = EventPublisher::publish_and_queue(
                        &pool,
                        job_queue,
                        EventType::ProjectStatusChanged,
                        "project",
                        project.base.id,
                        Some(("team_profile", user.user_id)),
                        Some(serde_json::json!({
                            "old_status": format!("{:?}", old),
                            "new_status": format!("{:?}", new)
                        })),
                    )
                    .await;
                }
            }
        }

        Ok(ProjectType::from(project))
    }

    /// Delete a project
    async fn delete_project(&self, ctx: &Context<'_>, id: Uuid) -> Result<bool> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Delete team member assignments first
        sqlx::query("DELETE FROM project_team_members WHERE project_id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Delete project scope tasks, categories, and scopes
        let scope_ids: Vec<Uuid> = sqlx::query_scalar(
            "SELECT id FROM project_scopes WHERE project_id = $1",
        )
        .bind(id)
        .fetch_all(&*pool)
        .await?;

        for scope_id in scope_ids {
            let category_ids: Vec<Uuid> = sqlx::query_scalar(
                "SELECT id FROM project_scope_categories WHERE scope_id = $1",
            )
            .bind(scope_id)
            .fetch_all(&*pool)
            .await?;

            for category_id in category_ids {
                sqlx::query("DELETE FROM project_scope_tasks WHERE category_id = $1")
                    .bind(category_id)
                    .execute(&*pool)
                    .await?;
            }

            sqlx::query("DELETE FROM project_scope_categories WHERE scope_id = $1")
                .bind(scope_id)
                .execute(&*pool)
                .await?;
        }

        sqlx::query("DELETE FROM project_scopes WHERE project_id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Delete the project
        let result = sqlx::query("DELETE FROM projects WHERE id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Publish ProjectDeleted event
        if result.rows_affected() > 0 {
            if let (Ok(user), Ok(job_queue)) = (ctx.data::<UserContext>(), ctx.data::<JobQueue>()) {
                let _ = EventPublisher::publish_and_queue(
                    &pool,
                    job_queue,
                    EventType::ProjectDeleted,
                    "project",
                    id,
                    Some(("team_profile", user.user_id)),
                    None,
                )
                .await;
            }
        }

        Ok(result.rows_affected() > 0)
    }

    /// Assign a team member to a project
    async fn assign_project_team_member(
        &self,
        ctx: &Context<'_>,
        project_id: Uuid,
        team_profile_id: Uuid,
    ) -> Result<ProjectTeamMemberType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let member: ProjectTeamMember = sqlx::query_as::<_, ProjectTeamMember>(
            r#"
            INSERT INTO project_team_members (id, project_id, team_profile_id, created_at)
            VALUES (gen_random_uuid(), $1, $2, NOW())
            ON CONFLICT (project_id, team_profile_id) DO UPDATE SET project_id = EXCLUDED.project_id
            RETURNING id, project_id, team_profile_id, created_at
            "#,
        )
        .bind(project_id)
        .bind(team_profile_id)
        .fetch_one(&*pool)
        .await?;

        // Publish ProjectAssigned event
        if let (Ok(user), Ok(job_queue)) = (ctx.data::<UserContext>(), ctx.data::<JobQueue>()) {
            let _ = EventPublisher::publish_and_queue(
                &pool,
                job_queue,
                EventType::ProjectAssigned,
                "project",
                project_id,
                Some(("team_profile", user.user_id)),
                Some(serde_json::json!({
                    "assigned_team_profile_id": team_profile_id.to_string()
                })),
            )
            .await;
        }

        Ok(ProjectTeamMemberType::from(member))
    }

    /// Remove a team member assignment from a project
    async fn remove_project_team_member(&self, ctx: &Context<'_>, id: Uuid) -> Result<bool> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get the project_id and team_profile_id before deleting
        let assignment: Option<(Uuid, Uuid)> = sqlx::query_as(
            "SELECT project_id, team_profile_id FROM project_team_members WHERE id = $1",
        )
        .bind(id)
        .fetch_optional(&*pool)
        .await?;

        let result = sqlx::query("DELETE FROM project_team_members WHERE id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Publish ProjectUnassigned event
        if result.rows_affected() > 0 {
            if let Some((project_id, team_profile_id)) = assignment {
                if let (Ok(user), Ok(job_queue)) = (ctx.data::<UserContext>(), ctx.data::<JobQueue>()) {
                    let _ = EventPublisher::publish_and_queue(
                        &pool,
                        job_queue,
                        EventType::ProjectUnassigned,
                        "project",
                        project_id,
                        Some(("team_profile", user.user_id)),
                        Some(serde_json::json!({
                            "unassigned_team_profile_id": team_profile_id.to_string()
                        })),
                    )
                    .await;
                }
            }
        }

        Ok(result.rows_affected() > 0)
    }

    // ==================== PROJECT SCOPE MUTATIONS ====================

    /// Create a new scope for a project (ONE scope per project - deactivates existing)
    async fn create_project_scope(
        &self,
        ctx: &Context<'_>,
        project_id: Uuid,
        input: CreateProjectScopeInput,
    ) -> Result<ProjectScopeType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get project's account_address_id and account_id if it has one
        let project: Project = sqlx::query_as::<_, Project>(
            r#"
            SELECT id, created_at, updated_at, customer_id, name, date, status, labor, amount,
                   notes, calendar_event_id, wave_service_id, account_address_id,
                   street_address, city, state, zip_code
            FROM projects WHERE id = $1
            "#,
        )
        .bind(project_id)
        .fetch_one(&*pool)
        .await?;

        // Get account_id from account_address if present
        let account_id: Option<Uuid> = if let Some(address_id) = project.account_address_id {
            sqlx::query_scalar("SELECT account_id FROM account_addresses WHERE id = $1")
                .bind(address_id)
                .fetch_optional(&*pool)
                .await?
        } else {
            None
        };

        // Deactivate any existing active scopes for this project
        sqlx::query(
            r#"
            UPDATE project_scopes
            SET is_active = false, updated_at = NOW()
            WHERE project_id = $1 AND is_active = true
            "#,
        )
        .bind(project_id)
        .execute(&*pool)
        .await?;

        // Create the scope
        let scope: ProjectScope = sqlx::query_as::<_, ProjectScope>(
            r#"
            INSERT INTO project_scopes (
                id, created_at, updated_at, name, project_id, account_id, account_address_id, description, is_active
            )
            VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3, $4, $5, true)
            RETURNING id, created_at, updated_at, name, project_id, account_id, account_address_id, description, is_active
            "#,
        )
        .bind(&input.name)
        .bind(project_id)
        .bind(account_id)
        .bind(project.account_address_id)
        .bind(&input.description)
        .fetch_one(&*pool)
        .await?;

        // Create categories and tasks if provided
        if let Some(categories) = input.categories {
            for (cat_order, cat_input) in categories.into_iter().enumerate() {
                let category: ProjectScopeCategory = sqlx::query_as::<_, ProjectScopeCategory>(
                    r#"
                    INSERT INTO project_scope_categories (id, created_at, updated_at, scope_id, name, "order")
                    VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3)
                    RETURNING id, created_at, updated_at, scope_id, name, "order"
                    "#,
                )
                .bind(scope.base.id)
                .bind(&cat_input.name)
                .bind(cat_input.order.unwrap_or(cat_order as i32))
                .fetch_one(&*pool)
                .await?;

                if let Some(tasks) = cat_input.tasks {
                    for (task_order, task_input) in tasks.into_iter().enumerate() {
                        sqlx::query(
                            r#"
                            INSERT INTO project_scope_tasks (
                                id, created_at, updated_at, category_id, scope_description,
                                checklist_description, session_description, "order", estimated_minutes
                            )
                            VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3, $4, $5, $6)
                            "#,
                        )
                        .bind(category.base.id)
                        .bind(&task_input.scope_description)
                        .bind(task_input.checklist_description.as_deref().unwrap_or(&task_input.scope_description))
                        .bind(task_input.session_description.as_deref().unwrap_or(&task_input.scope_description))
                        .bind(task_input.order.unwrap_or(task_order as i32))
                        .bind(task_input.estimated_minutes)
                        .execute(&*pool)
                        .await?;
                    }
                }
            }
        }

        Ok(ProjectScopeType::from(scope))
    }

    /// Update a project scope
    async fn update_project_scope(
        &self,
        ctx: &Context<'_>,
        id: Uuid,
        input: UpdateProjectScopeInput,
    ) -> Result<ProjectScopeType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // If activating this scope, deactivate others for same project
        if input.is_active == Some(true) {
            let project_id: Uuid = sqlx::query_scalar(
                "SELECT project_id FROM project_scopes WHERE id = $1",
            )
            .bind(id)
            .fetch_one(&*pool)
            .await?;

            sqlx::query(
                r#"
                UPDATE project_scopes
                SET is_active = false, updated_at = NOW()
                WHERE project_id = $1 AND id != $2 AND is_active = true
                "#,
            )
            .bind(project_id)
            .bind(id)
            .execute(&*pool)
            .await?;
        }

        let scope: ProjectScope = sqlx::query_as::<_, ProjectScope>(
            r#"
            UPDATE project_scopes
            SET
                name = COALESCE($2, name),
                description = COALESCE($3, description),
                is_active = COALESCE($4, is_active),
                updated_at = NOW()
            WHERE id = $1
            RETURNING id, created_at, updated_at, name, project_id, account_id, account_address_id, description, is_active
            "#,
        )
        .bind(id)
        .bind(&input.name)
        .bind(&input.description)
        .bind(input.is_active)
        .fetch_one(&*pool)
        .await?;

        Ok(ProjectScopeType::from(scope))
    }

    /// Delete a project scope (hard delete since sessions are tracked separately)
    async fn delete_project_scope(&self, ctx: &Context<'_>, id: Uuid) -> Result<bool> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get all category IDs for this scope
        let category_ids: Vec<Uuid> = sqlx::query_scalar(
            "SELECT id FROM project_scope_categories WHERE scope_id = $1",
        )
        .bind(id)
        .fetch_all(&*pool)
        .await?;

        // Delete tasks for all categories
        for category_id in &category_ids {
            sqlx::query("DELETE FROM project_scope_tasks WHERE category_id = $1")
                .bind(category_id)
                .execute(&*pool)
                .await?;
        }

        // Delete categories
        sqlx::query("DELETE FROM project_scope_categories WHERE scope_id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Delete scope
        let result = sqlx::query("DELETE FROM project_scopes WHERE id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        Ok(result.rows_affected() > 0)
    }

    // ==================== SCOPE CATEGORY MUTATIONS ====================

    /// Create a new category within a project scope
    async fn create_project_scope_category(
        &self,
        ctx: &Context<'_>,
        scope_id: Uuid,
        input: CreateProjectCategoryInput,
    ) -> Result<ProjectScopeCategoryType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get max order for existing categories
        let max_order: Option<i32> = sqlx::query_scalar(
            r#"SELECT MAX("order") FROM project_scope_categories WHERE scope_id = $1"#,
        )
        .bind(scope_id)
        .fetch_one(&*pool)
        .await?;

        let category: ProjectScopeCategory = sqlx::query_as::<_, ProjectScopeCategory>(
            r#"
            INSERT INTO project_scope_categories (id, created_at, updated_at, scope_id, name, "order")
            VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3)
            RETURNING id, created_at, updated_at, scope_id, name, "order"
            "#,
        )
        .bind(scope_id)
        .bind(&input.name)
        .bind(input.order.unwrap_or(max_order.unwrap_or(0) + 1))
        .fetch_one(&*pool)
        .await?;

        // Create tasks if provided
        if let Some(tasks) = input.tasks {
            for (task_order, task_input) in tasks.into_iter().enumerate() {
                sqlx::query(
                    r#"
                    INSERT INTO project_scope_tasks (
                        id, created_at, updated_at, category_id, scope_description,
                        checklist_description, session_description, "order", estimated_minutes
                    )
                    VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3, $4, $5, $6)
                    "#,
                )
                .bind(category.base.id)
                .bind(&task_input.scope_description)
                .bind(task_input.checklist_description.as_deref().unwrap_or(&task_input.scope_description))
                .bind(task_input.session_description.as_deref().unwrap_or(&task_input.scope_description))
                .bind(task_input.order.unwrap_or(task_order as i32))
                .bind(task_input.estimated_minutes)
                .execute(&*pool)
                .await?;
            }
        }

        Ok(ProjectScopeCategoryType::from(category))
    }

    /// Update a project scope category
    async fn update_project_scope_category(
        &self,
        ctx: &Context<'_>,
        id: Uuid,
        input: UpdateProjectCategoryInput,
    ) -> Result<ProjectScopeCategoryType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let category: ProjectScopeCategory = sqlx::query_as::<_, ProjectScopeCategory>(
            r#"
            UPDATE project_scope_categories
            SET
                name = COALESCE($2, name),
                "order" = COALESCE($3, "order"),
                updated_at = NOW()
            WHERE id = $1
            RETURNING id, created_at, updated_at, scope_id, name, "order"
            "#,
        )
        .bind(id)
        .bind(&input.name)
        .bind(input.order)
        .fetch_one(&*pool)
        .await?;

        Ok(ProjectScopeCategoryType::from(category))
    }

    /// Delete a project scope category (cascades to tasks)
    async fn delete_project_scope_category(&self, ctx: &Context<'_>, id: Uuid) -> Result<bool> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Delete tasks first
        sqlx::query("DELETE FROM project_scope_tasks WHERE category_id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        // Delete category
        let result = sqlx::query("DELETE FROM project_scope_categories WHERE id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        Ok(result.rows_affected() > 0)
    }

    // ==================== SCOPE TASK MUTATIONS ====================

    /// Create a new task within a project scope category
    /// Note: Project tasks don't have frequency - they are one-time tasks
    async fn create_project_scope_task(
        &self,
        ctx: &Context<'_>,
        category_id: Uuid,
        input: CreateProjectScopeTaskInput,
    ) -> Result<ProjectScopeTaskType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Get max order for existing tasks
        let max_order: Option<i32> = sqlx::query_scalar(
            r#"SELECT MAX("order") FROM project_scope_tasks WHERE category_id = $1"#,
        )
        .bind(category_id)
        .fetch_one(&*pool)
        .await?;

        let task: ProjectScopeTask = sqlx::query_as::<_, ProjectScopeTask>(
            r#"
            INSERT INTO project_scope_tasks (
                id, created_at, updated_at, category_id, scope_description,
                checklist_description, session_description, "order", estimated_minutes
            )
            VALUES (gen_random_uuid(), NOW(), NOW(), $1, $2, $3, $4, $5, $6)
            RETURNING id, created_at, updated_at, category_id, scope_description,
                checklist_description, session_description, "order", estimated_minutes
            "#,
        )
        .bind(category_id)
        .bind(&input.scope_description)
        .bind(input.checklist_description.as_deref().unwrap_or(&input.scope_description))
        .bind(input.session_description.as_deref().unwrap_or(&input.scope_description))
        .bind(input.order.unwrap_or(max_order.unwrap_or(0) + 1))
        .bind(input.estimated_minutes)
        .fetch_one(&*pool)
        .await?;

        Ok(ProjectScopeTaskType::from(task))
    }

    /// Update a project scope task
    async fn update_project_scope_task(
        &self,
        ctx: &Context<'_>,
        id: Uuid,
        input: UpdateProjectScopeTaskInput,
    ) -> Result<ProjectScopeTaskType> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let task: ProjectScopeTask = sqlx::query_as::<_, ProjectScopeTask>(
            r#"
            UPDATE project_scope_tasks
            SET
                scope_description = COALESCE($2, scope_description),
                checklist_description = COALESCE($3, checklist_description),
                session_description = COALESCE($4, session_description),
                "order" = COALESCE($5, "order"),
                estimated_minutes = COALESCE($6, estimated_minutes),
                updated_at = NOW()
            WHERE id = $1
            RETURNING id, created_at, updated_at, category_id, scope_description,
                checklist_description, session_description, "order", estimated_minutes
            "#,
        )
        .bind(id)
        .bind(&input.scope_description)
        .bind(&input.checklist_description)
        .bind(&input.session_description)
        .bind(input.order)
        .bind(input.estimated_minutes)
        .fetch_one(&*pool)
        .await?;

        Ok(ProjectScopeTaskType::from(task))
    }

    /// Delete a project scope task
    async fn delete_project_scope_task(&self, ctx: &Context<'_>, id: Uuid) -> Result<bool> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let result = sqlx::query("DELETE FROM project_scope_tasks WHERE id = $1")
            .bind(id)
            .execute(&*pool)
            .await?;

        Ok(result.rows_affected() > 0)
    }
}

