//! Session GraphQL types
//!
//! Types for service and project sessions, including notes, images, videos,
//! and task completions.

use async_graphql::{ComplexObject, Context, Result, SimpleObject};
use chrono::{DateTime, NaiveDate, Utc};
use uuid::Uuid;

use crate::db::Database;
use crate::graphql::mutations::project::ProjectScopeTaskType;
use crate::models::{
    ProjectSession, ProjectSessionImage, ProjectSessionNote, ProjectSessionVideo,
    ProjectScopeTask, ServiceSession, ServiceSessionImage,
    ServiceSessionNote, ServiceSessionVideo, ServiceScopeTask,
    TeamProfile,
};

use super::{ServiceScopeTaskType, TeamProfileType};

// ==================== SERVICE SESSION TYPES ====================

/// Service session - work session for a scheduled service
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ServiceSessionType {
    pub id: Uuid,
    pub service_id: Uuid,
    pub account_id: Uuid,
    pub account_address_id: Uuid,
    pub customer_id: Uuid,
    pub scope_id: Option<Uuid>,
    pub start: DateTime<Utc>,
    pub end: Option<DateTime<Utc>>,
    pub date: NaiveDate,
    pub created_by_id: Uuid,
    pub closed_by_id: Option<Uuid>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[ComplexObject]
impl ServiceSessionType {
    /// Whether the session is still active (not closed)
    async fn is_active(&self) -> bool {
        self.end.is_none()
    }

    /// Duration in seconds (if session is closed)
    async fn duration_seconds(&self) -> Option<i64> {
        self.end.map(|end| (end - self.start).num_seconds())
    }

    /// Team profile who created/started the session
    async fn created_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.created_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }

    /// Team profile who closed the session (if closed)
    async fn closed_by(&self, ctx: &Context<'_>) -> Result<Option<TeamProfileType>> {
        let Some(closed_by_id) = self.closed_by_id else {
            return Ok(None);
        };

        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(closed_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }

    /// Notes attached to this session
    async fn notes(&self, ctx: &Context<'_>) -> Result<Vec<ServiceSessionNoteType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let notes: Vec<ServiceSessionNote> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, content, author_id, internal
            FROM service_session_notes
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(notes.into_iter().map(ServiceSessionNoteType::from).collect())
    }

    /// Images attached to this session
    async fn images(&self, ctx: &Context<'_>) -> Result<Vec<ServiceSessionImageType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let images: Vec<ServiceSessionImage> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, title, image, thumbnail,
                   content_type, width, height,
                   uploaded_by_team_profile_id AS uploaded_by_id,
                   notes, internal
            FROM service_session_images
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(images.into_iter().map(ServiceSessionImageType::from).collect())
    }

    /// Videos attached to this session
    async fn videos(&self, ctx: &Context<'_>) -> Result<Vec<ServiceSessionVideoType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let videos: Vec<ServiceSessionVideo> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, title, video, thumbnail,
                   content_type, width, height,
                   uploaded_by_team_profile_id AS uploaded_by_id,
                   notes, internal, duration_seconds, file_size_bytes
            FROM service_session_videos
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(videos.into_iter().map(ServiceSessionVideoType::from).collect())
    }

    /// Task completions recorded in this session
    async fn completed_tasks(&self, ctx: &Context<'_>) -> Result<Vec<ServiceTaskCompletionType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Task completions are linked via service_session_completed_tasks join table
        // Query directly into a tuple since we need session_id from the join
        let rows: Vec<(Uuid, Uuid, Uuid, DateTime<Utc>, Option<String>)> = sqlx::query_as(
            r#"
            SELECT tc.id, tc.task_id, tc.completed_by_id, tc.completed_at, tc.notes
            FROM service_task_completions tc
            JOIN service_session_completed_tasks sct ON sct.task_completion_id = tc.id
            WHERE sct.session_id = $1
            ORDER BY tc.completed_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(rows
            .into_iter()
            .map(|(id, task_id, completed_by_id, completed_at, notes)| {
                ServiceTaskCompletionType {
                    id,
                    session_id: self.id,
                    task_id,
                    completed_by_id,
                    completed_at,
                    notes,
                }
            })
            .collect())
    }
}

impl From<ServiceSession> for ServiceSessionType {
    fn from(session: ServiceSession) -> Self {
        Self {
            id: session.base.id,
            service_id: session.service_id,
            account_id: session.account_id,
            account_address_id: session.account_address_id,
            customer_id: session.customer_id,
            scope_id: session.scope_id,
            start: session.start,
            end: session.end,
            date: session.date,
            created_by_id: session.created_by_id,
            closed_by_id: session.closed_by_id,
            created_at: session.base.created_at,
            updated_at: session.base.updated_at,
        }
    }
}

/// Note attached to a service session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ServiceSessionNoteType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub content: String,
    pub author_id: Uuid,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[ComplexObject]
impl ServiceSessionNoteType {
    /// Author of the note
    async fn author(&self, ctx: &Context<'_>) -> Result<Option<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(self.author_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ServiceSessionNote> for ServiceSessionNoteType {
    fn from(note: ServiceSessionNote) -> Self {
        Self {
            id: note.base.id,
            session_id: note.session_id,
            content: note.note.content,
            author_id: note.note.author_id,
            internal: note.note.internal,
            created_at: note.base.created_at,
            updated_at: note.base.updated_at,
        }
    }
}

/// Image attached to a service session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ServiceSessionImageType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub title: Option<String>,
    /// Path to original image (use with /api/media/ prefix)
    pub image: String,
    /// Path to thumbnail (use with /api/media/ prefix)
    pub thumbnail: Option<String>,
    pub content_type: String,
    pub width: Option<i32>,
    pub height: Option<i32>,
    pub uploaded_by_id: Uuid,
    pub notes: Option<String>,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
}

#[ComplexObject]
impl ServiceSessionImageType {
    /// User who uploaded the image
    async fn uploaded_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.uploaded_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ServiceSessionImage> for ServiceSessionImageType {
    fn from(image: ServiceSessionImage) -> Self {
        Self {
            id: image.base.id,
            session_id: image.session_id,
            title: image.title,
            image: image.image,
            thumbnail: image.thumbnail,
            content_type: image.media.content_type,
            width: image.media.width,
            height: image.media.height,
            uploaded_by_id: image.media.uploaded_by_id,
            notes: image.media.notes,
            internal: image.media.internal,
            created_at: image.base.created_at,
        }
    }
}

/// Video attached to a service session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ServiceSessionVideoType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub title: Option<String>,
    /// Path to video file (use with /api/media/ prefix)
    pub video: String,
    /// Path to thumbnail (use with /api/media/ prefix)
    pub thumbnail: Option<String>,
    pub content_type: String,
    pub width: Option<i32>,
    pub height: Option<i32>,
    pub duration_seconds: Option<i32>,
    pub file_size_bytes: Option<i64>,
    pub uploaded_by_id: Uuid,
    pub notes: Option<String>,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
}

#[ComplexObject]
impl ServiceSessionVideoType {
    /// User who uploaded the video
    async fn uploaded_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.uploaded_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ServiceSessionVideo> for ServiceSessionVideoType {
    fn from(video: ServiceSessionVideo) -> Self {
        Self {
            id: video.base.id,
            session_id: video.session_id,
            title: video.title,
            video: video.video,
            thumbnail: video.thumbnail,
            content_type: video.media.content_type,
            width: video.media.width,
            height: video.media.height,
            duration_seconds: video.duration_seconds,
            file_size_bytes: video.file_size_bytes,
            uploaded_by_id: video.media.uploaded_by_id,
            notes: video.media.notes,
            internal: video.media.internal,
            created_at: video.base.created_at,
        }
    }
}

/// Task completion record for a service session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ServiceTaskCompletionType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub task_id: Uuid,
    pub completed_by_id: Uuid,
    pub completed_at: DateTime<Utc>,
    pub notes: Option<String>,
}

#[ComplexObject]
impl ServiceTaskCompletionType {
    /// The task that was completed
    async fn task(&self, ctx: &Context<'_>) -> Result<Option<ServiceScopeTaskType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let task = sqlx::query_as::<_, ServiceScopeTask>(
            r#"
            SELECT id, created_at, updated_at, area_id, scope_description, checklist_description,
                   session_description, frequency, "order", estimated_minutes
            FROM service_scope_tasks
            WHERE id = $1
            "#,
        )
        .bind(self.task_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(task.map(ServiceScopeTaskType::from))
    }

    /// Team member who completed the task
    async fn completed_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.completed_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}


// ==================== PROJECT SESSION TYPES ====================

/// Project session - work session for a scheduled project
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ProjectSessionType {
    pub id: Uuid,
    pub project_id: Uuid,
    pub account_id: Option<Uuid>,
    pub account_address_id: Option<Uuid>,
    pub customer_id: Uuid,
    pub scope_id: Option<Uuid>,
    pub start: DateTime<Utc>,
    pub end: Option<DateTime<Utc>>,
    pub date: NaiveDate,
    pub created_by_id: Uuid,
    pub closed_by_id: Option<Uuid>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[ComplexObject]
impl ProjectSessionType {
    /// Whether the session is still active (not closed)
    async fn is_active(&self) -> bool {
        self.end.is_none()
    }

    /// Duration in seconds (if session is closed)
    async fn duration_seconds(&self) -> Option<i64> {
        self.end.map(|end| (end - self.start).num_seconds())
    }

    /// Team profile who created/started the session
    async fn created_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.created_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }

    /// Team profile who closed the session (if closed)
    async fn closed_by(&self, ctx: &Context<'_>) -> Result<Option<TeamProfileType>> {
        let Some(closed_by_id) = self.closed_by_id else {
            return Ok(None);
        };

        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(closed_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }

    /// Notes attached to this session
    async fn notes(&self, ctx: &Context<'_>) -> Result<Vec<ProjectSessionNoteType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let notes: Vec<ProjectSessionNote> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, content, author_id, internal
            FROM project_session_notes
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(notes.into_iter().map(ProjectSessionNoteType::from).collect())
    }

    /// Images attached to this session
    async fn images(&self, ctx: &Context<'_>) -> Result<Vec<ProjectSessionImageType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let images: Vec<ProjectSessionImage> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, title, image, thumbnail,
                   content_type, width, height,
                   uploaded_by_team_profile_id AS uploaded_by_id,
                   notes, internal
            FROM project_session_images
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(images.into_iter().map(ProjectSessionImageType::from).collect())
    }

    /// Videos attached to this session
    async fn videos(&self, ctx: &Context<'_>) -> Result<Vec<ProjectSessionVideoType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let videos: Vec<ProjectSessionVideo> = sqlx::query_as(
            r#"
            SELECT id, created_at, updated_at, session_id, title, video, thumbnail,
                   content_type, width, height,
                   uploaded_by_team_profile_id AS uploaded_by_id,
                   notes, internal, duration_seconds, file_size_bytes
            FROM project_session_videos
            WHERE session_id = $1
            ORDER BY created_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(videos.into_iter().map(ProjectSessionVideoType::from).collect())
    }

    /// Task completions recorded in this session
    async fn completed_tasks(&self, ctx: &Context<'_>) -> Result<Vec<ProjectTaskCompletionType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        // Task completions are linked via project_session_completed_tasks join table
        // Query directly into a tuple since we need session_id from the join
        let rows: Vec<(Uuid, Uuid, Uuid, DateTime<Utc>, Option<String>)> = sqlx::query_as(
            r#"
            SELECT tc.id, tc.task_id, tc.completed_by_id, tc.completed_at, tc.notes
            FROM project_task_completions tc
            JOIN project_session_completed_tasks pct ON pct.task_completion_id = tc.id
            WHERE pct.session_id = $1
            ORDER BY tc.completed_at DESC
            "#,
        )
        .bind(self.id)
        .fetch_all(&*pool)
        .await?;

        Ok(rows
            .into_iter()
            .map(|(id, task_id, completed_by_id, completed_at, notes)| {
                ProjectTaskCompletionType {
                    id,
                    session_id: self.id,
                    task_id,
                    completed_by_id,
                    completed_at,
                    notes,
                }
            })
            .collect())
    }
}

impl From<ProjectSession> for ProjectSessionType {
    fn from(session: ProjectSession) -> Self {
        Self {
            id: session.base.id,
            project_id: session.project_id,
            account_id: session.account_id,
            account_address_id: session.account_address_id,
            customer_id: session.customer_id,
            scope_id: session.scope_id,
            start: session.start,
            end: session.end,
            date: session.date,
            created_by_id: session.created_by_id,
            closed_by_id: session.closed_by_id,
            created_at: session.base.created_at,
            updated_at: session.base.updated_at,
        }
    }
}

/// Note attached to a project session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ProjectSessionNoteType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub content: String,
    pub author_id: Uuid,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[ComplexObject]
impl ProjectSessionNoteType {
    /// Author of the note
    async fn author(&self, ctx: &Context<'_>) -> Result<Option<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(self.author_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ProjectSessionNote> for ProjectSessionNoteType {
    fn from(note: ProjectSessionNote) -> Self {
        Self {
            id: note.base.id,
            session_id: note.session_id,
            content: note.note.content,
            author_id: note.note.author_id,
            internal: note.note.internal,
            created_at: note.base.created_at,
            updated_at: note.base.updated_at,
        }
    }
}

/// Image attached to a project session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ProjectSessionImageType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub title: Option<String>,
    /// Path to original image (use with /api/media/ prefix)
    pub image: String,
    /// Path to thumbnail (use with /api/media/ prefix)
    pub thumbnail: Option<String>,
    pub content_type: String,
    pub width: Option<i32>,
    pub height: Option<i32>,
    pub uploaded_by_id: Uuid,
    pub notes: Option<String>,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
}

#[ComplexObject]
impl ProjectSessionImageType {
    /// User who uploaded the image
    async fn uploaded_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.uploaded_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ProjectSessionImage> for ProjectSessionImageType {
    fn from(image: ProjectSessionImage) -> Self {
        Self {
            id: image.base.id,
            session_id: image.session_id,
            title: image.title,
            image: image.image,
            thumbnail: image.thumbnail,
            content_type: image.media.content_type,
            width: image.media.width,
            height: image.media.height,
            uploaded_by_id: image.media.uploaded_by_id,
            notes: image.media.notes,
            internal: image.media.internal,
            created_at: image.base.created_at,
        }
    }
}

/// Video attached to a project session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ProjectSessionVideoType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub title: Option<String>,
    /// Path to video file (use with /api/media/ prefix)
    pub video: String,
    /// Path to thumbnail (use with /api/media/ prefix)
    pub thumbnail: Option<String>,
    pub content_type: String,
    pub width: Option<i32>,
    pub height: Option<i32>,
    pub duration_seconds: Option<i32>,
    pub file_size_bytes: Option<i64>,
    pub uploaded_by_id: Uuid,
    pub notes: Option<String>,
    pub internal: bool,
    pub created_at: DateTime<Utc>,
}

#[ComplexObject]
impl ProjectSessionVideoType {
    /// User who uploaded the video
    async fn uploaded_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.uploaded_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

impl From<ProjectSessionVideo> for ProjectSessionVideoType {
    fn from(video: ProjectSessionVideo) -> Self {
        Self {
            id: video.base.id,
            session_id: video.session_id,
            title: video.title,
            video: video.video,
            thumbnail: video.thumbnail,
            content_type: video.media.content_type,
            width: video.media.width,
            height: video.media.height,
            duration_seconds: video.duration_seconds,
            file_size_bytes: video.file_size_bytes,
            uploaded_by_id: video.media.uploaded_by_id,
            notes: video.media.notes,
            internal: video.media.internal,
            created_at: video.base.created_at,
        }
    }
}

/// Task completion record for a project session
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct ProjectTaskCompletionType {
    pub id: Uuid,
    pub session_id: Uuid,
    pub task_id: Uuid,
    pub completed_by_id: Uuid,
    pub completed_at: DateTime<Utc>,
    pub notes: Option<String>,
}

#[ComplexObject]
impl ProjectTaskCompletionType {
    /// The task that was completed
    async fn task(&self, ctx: &Context<'_>) -> Result<Option<ProjectScopeTaskType>> {
        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        let task = 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 id = $1
            "#,
        )
        .bind(self.task_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(task.map(ProjectScopeTaskType::from))
    }

    /// Team member who completed the task
    async fn completed_by(&self, ctx: &Context<'_>) -> Result<Option<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(self.completed_by_id)
        .fetch_optional(&*pool)
        .await?;

        Ok(profile.map(TeamProfileType::from))
    }
}

