use axum::{
    extract::{Multipart, Path, Query, State},
    http::StatusCode,
    response::Json,
    routing::{get, post},
    Router,
};
use serde::{Deserialize, Serialize};

use uuid::Uuid;

use crate::core::db::{schema, Database, PostgresDb};
use crate::core::processor::face_recognition::{
    process_face_recognition, register_face, FaceRecognitionResult, FaceRegistrationResult,
};

#[derive(Debug, Deserialize)]
pub struct FaceRecognitionRequest {
    pub video_uuid: String,
    pub enable_recognition: Option<bool>,
    pub enable_tracking: Option<bool>,
    pub enable_clustering: Option<bool>,
    pub database_path: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct FaceRecognitionResponse {
    pub success: bool,
    pub message: String,
    pub result: Option<FaceRecognitionResult>,
    pub processing_id: String,
}

#[derive(Debug, Deserialize)]
pub struct FaceRegistrationRequest {
    pub video_uuid: String,
    pub name: String,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub struct FaceRegistrationApiResponse {
    pub success: bool,
    pub message: String,
    pub result: Option<FaceRegistrationResult>,
}

#[derive(Debug, Deserialize)]
pub struct FaceSearchRequest {
    pub video_uuid: String,
    pub embedding: Vec<f32>,
    pub similarity_threshold: Option<f64>,
    pub limit: Option<i32>,
}

#[derive(Debug, Serialize)]
pub struct FaceSearchResponse {
    pub success: bool,
    pub message: String,
    pub results: Vec<FaceSearchResult>,
}

#[derive(Debug, Serialize)]
pub struct FaceSearchResult {
    pub face_id: String,
    pub name: Option<String>,
    pub similarity: f64,
    pub attributes: Option<serde_json::Value>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize)]
pub struct FaceListQuery {
    pub video_uuid: String,
    pub page: Option<usize>,
    pub page_size: Option<usize>,
    pub active_only: Option<bool>,
}

#[derive(Debug, Serialize)]
pub struct FaceListResponse {
    pub success: bool,
    pub message: String,
    pub faces: Vec<FaceListItem>,
    pub count: i64,
    pub page: usize,
    pub page_size: usize,
}

#[derive(Debug, Serialize)]
pub struct FaceListItem {
    pub face_id: String,
    pub name: Option<String>,
    pub created_at: String,
    pub updated_at: String,
    pub is_active: bool,
    pub metadata: Option<serde_json::Value>,
}

pub fn face_recognition_routes() -> Router<crate::api::server::AppState> {
    Router::new()
        .route("/api/v1/face/recognize", post(recognize_faces))
        .route("/api/v1/face/register", post(register_face_api))
        .route("/api/v1/face/search", post(search_faces))
        .route("/api/v1/face/list", get(list_faces))
        .route("/api/v1/face/:face_id", get(get_face_details))
        .route("/api/v1/face/:face_id", axum::routing::delete(delete_face))
        .route(
            "/api/v1/face/results/:video_uuid",
            get(get_recognition_results),
        )
}

async fn recognize_faces(
    State(_state): State<crate::api::server::AppState>,
    Json(request): Json<FaceRecognitionRequest>,
) -> Result<Json<FaceRecognitionResponse>, (StatusCode, String)> {
    let processing_id = Uuid::new_v4().to_string();

    tracing::info!(
        "[FACE_RECOGNITION] Starting recognition for video: {}, processing_id: {}",
        request.video_uuid,
        processing_id
    );

    // Get video path from database
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    let video_record = match db.get_video_by_uuid(&request.video_uuid).await {
        Ok(Some(record)) => record,
        Ok(None) => {
            return Err((
                StatusCode::NOT_FOUND,
                format!("Video not found: {}", request.video_uuid),
            ))
        }
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to fetch video: {}", e),
            ))
        }
    };

    let video_path = video_record.file_path;
    let output_path = format!(
        "{}/face_recognition_{}.json",
        crate::core::config::OUTPUT_DIR.as_str(),
        processing_id
    );

    // Process face recognition
    let result = match process_face_recognition(
        &video_path,
        &output_path,
        Some(&processing_id),
        request.enable_recognition.unwrap_or(true),
        request.enable_tracking.unwrap_or(true),
        request.enable_clustering.unwrap_or(true),
    )
    .await
    {
        Ok(result) => result,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Face recognition failed: {}", e),
            ))
        }
    };

    // Store results in database
    if let Err(e) = store_recognition_results(&db, &request.video_uuid, &result).await {
        tracing::warn!("Failed to store recognition results: {}", e);
    }

    Ok(Json(FaceRecognitionResponse {
        success: true,
        message: format!("Face recognition completed for {}", request.video_uuid),
        result: Some(result),
        processing_id,
    }))
}

async fn register_face_api(
    State(_state): State<crate::api::server::AppState>,
    mut multipart: Multipart,
) -> Result<Json<FaceRegistrationApiResponse>, (StatusCode, String)> {
    let mut image_path: Option<String> = None;
    let mut name: Option<String> = None;
    let mut metadata: Option<serde_json::Value> = None;

    // Parse multipart form data
    while let Some(field) = multipart.next_field().await.map_err(|e| {
        (
            StatusCode::BAD_REQUEST,
            format!("Failed to parse form data: {}", e),
        )
    })? {
        let field_name = field.name().unwrap_or("").to_string();

        match field_name.as_str() {
            "image" => {
                // Save uploaded image
                let file_name = format!("face_registration_{}.jpg", Uuid::new_v4());
                let file_path = format!("/tmp/{}", file_name);

                let data = field.bytes().await.map_err(|e| {
                    (
                        StatusCode::BAD_REQUEST,
                        format!("Failed to read image data: {}", e),
                    )
                })?;

                tokio::fs::write(&file_path, &data).await.map_err(|e| {
                    (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        format!("Failed to save image: {}", e),
                    )
                })?;

                image_path = Some(file_path);
            }
            "name" => {
                let value = field.text().await.map_err(|e| {
                    (
                        StatusCode::BAD_REQUEST,
                        format!("Failed to read name: {}", e),
                    )
                })?;
                name = Some(value);
            }
            "metadata" => {
                let value = field.text().await.map_err(|e| {
                    (
                        StatusCode::BAD_REQUEST,
                        format!("Failed to read metadata: {}", e),
                    )
                })?;
                metadata = Some(serde_json::from_str(&value).map_err(|e| {
                    (
                        StatusCode::BAD_REQUEST,
                        format!("Invalid JSON metadata: {}", e),
                    )
                })?);
            }
            _ => {}
        }
    }

    // Validate required fields
    let image_path =
        image_path.ok_or((StatusCode::BAD_REQUEST, "Image is required".to_string()))?;

    let name = name.ok_or((StatusCode::BAD_REQUEST, "Name is required".to_string()))?;

    // Register face
    let result = match register_face(&image_path, &name, metadata.clone()).await {
        Ok(result) => result,
        Err(e) => {
            // Clean up temporary file
            let _ = tokio::fs::remove_file(&image_path).await;
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Face registration failed: {}", e),
            ));
        }
    };

    // Clean up temporary file
    let _ = tokio::fs::remove_file(&image_path).await;

    // Store in PostgreSQL face_identities table
    if result.success && !result.embedding.is_empty() {
        let db = match PostgresDb::init().await {
            Ok(db) => db,
            Err(e) => {
                tracing::warn!("[FACE_REGISTRATION] Failed to connect to DB: {}", e);
                // Return success even if DB write fails (embedding is still in JSON output)
                return Ok(Json(FaceRegistrationApiResponse {
                    success: result.success,
                    message: format!("{} (Warning: DB write failed: {})", result.message, e),
                    result: Some(result),
                }));
            }
        };

        // Convert embedding to PostgreSQL vector format
        let embedding_str = format!(
            "[{}]",
            result
                .embedding
                .iter()
                .map(|v| v.to_string())
                .collect::<Vec<_>>()
                .join(",")
        );

        // Insert into face_identities
        let face_identities_table = schema::table_name("face_identities");
        let attrs_json =
            serde_json::to_string(&result.attributes).unwrap_or_else(|_| "{}".to_string());
        // Use public.vector type to work across schemas
        let vector_type = if schema::SCHEMA_PREFIX.as_str().is_empty() {
            "vector".to_string()
        } else {
            "public.vector".to_string()
        };
        let insert_query = format!(
            r#"
            INSERT INTO {} (face_id, name, embedding, attributes, metadata, is_active)
            VALUES ($1, $2, $3::{}, $4::jsonb, $5, TRUE)
            ON CONFLICT (face_id) DO UPDATE SET
                name = EXCLUDED.name,
                embedding = EXCLUDED.embedding,
                attributes = EXCLUDED.attributes,
                metadata = COALESCE(EXCLUDED.metadata, {}.metadata),
                updated_at = CURRENT_TIMESTAMP,
                is_active = TRUE
        "#,
            face_identities_table, vector_type, face_identities_table
        );

        match sqlx::query(&insert_query)
            .bind(&result.face_id)
            .bind(&name)
            .bind(&embedding_str)
            .bind(&attrs_json)
            .bind(&metadata.unwrap_or(serde_json::json!({})))
            .execute(db.pool())
            .await
        {
            Ok(_) => {
                tracing::info!(
                    "[FACE_REGISTRATION] Stored face '{}' (face_id={}) in DB",
                    name,
                    result.face_id
                );
            }
            Err(e) => {
                tracing::warn!("[FACE_REGISTRATION] Failed to store face in DB: {}", e);
            }
        }
    }

    Ok(Json(FaceRegistrationApiResponse {
        success: result.success,
        message: result.message.clone(),
        result: Some(result),
    }))
}

async fn search_faces(
    State(_state): State<crate::api::server::AppState>,
    Json(request): Json<FaceSearchRequest>,
) -> Result<Json<FaceSearchResponse>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    // Convert embedding to PostgreSQL vector format
    let embedding_str = format!(
        "[{}]",
        request
            .embedding
            .iter()
            .map(|v| v.to_string())
            .collect::<Vec<_>>()
            .join(",")
    );

    let similarity_threshold = request.similarity_threshold.unwrap_or(0.6);
    let limit = request.limit.unwrap_or(10);

    // Search for similar faces
    let face_identities_table = schema::table_name("face_identities");
    let vector_type = if schema::SCHEMA_PREFIX.as_str().is_empty() {
        "vector".to_string()
    } else {
        "public.vector".to_string()
    };
    let query = format!(
        r#"
        SELECT 
            face_id,
            name,
            1 - (embedding <=> $1::{}) as similarity,
            attributes,
            metadata
        FROM {}
        WHERE is_active = TRUE
          AND embedding IS NOT NULL
          AND 1 - (embedding <=> $1::{}) >= $2
        ORDER BY embedding <=> $1::{}
        LIMIT $3
    "#,
        vector_type, face_identities_table, vector_type, vector_type
    );

    let results: Vec<FaceSearchResult> = match sqlx::query_as::<
        _,
        (
            String,
            Option<String>,
            f64,
            Option<serde_json::Value>,
            Option<serde_json::Value>,
        ),
    >(query.as_str())
    .bind(&embedding_str)
    .bind(similarity_threshold)
    .bind(limit)
    .fetch_all(db.pool())
    .await
    {
        Ok(rows) => rows
            .into_iter()
            .map(
                |(face_id, name, similarity, attributes, metadata)| FaceSearchResult {
                    face_id,
                    name,
                    similarity,
                    attributes,
                    metadata,
                },
            )
            .collect(),
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to search faces: {}", e),
            ))
        }
    };

    Ok(Json(FaceSearchResponse {
        success: true,
        message: format!("Found {} similar faces", results.len()),
        results,
    }))
}

async fn list_faces(
    State(_state): State<crate::api::server::AppState>,
    Query(query): Query<FaceListQuery>,
) -> Result<Json<FaceListResponse>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    let page = query.page.unwrap_or(1);
    let page_size = query.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);
    let active_only = query.active_only.unwrap_or(true);

    // Build query
    let mut where_clause = "WHERE 1=1".to_string();
    if active_only {
        where_clause.push_str(" AND is_active = TRUE");
    }

    let face_identities_table = schema::table_name("face_identities");
    let count_query = format!(
        "SELECT COUNT(*) FROM {} {}",
        face_identities_table, where_clause
    );
    let list_query = format!(
        "SELECT face_id, name, created_at, updated_at, is_active, metadata FROM {} {} ORDER BY created_at DESC LIMIT $1 OFFSET $2",
        face_identities_table, where_clause
    );

    // Get total count
    let total: i64 = match sqlx::query_scalar(&count_query).fetch_one(db.pool()).await {
        Ok(count) => count,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to count faces: {}", e),
            ))
        }
    };

    // Get face list
    let faces: Vec<FaceListItem> = match sqlx::query_as::<
        _,
        (
            String,
            Option<String>,
            chrono::DateTime<chrono::Utc>,
            chrono::DateTime<chrono::Utc>,
            bool,
            Option<serde_json::Value>,
        ),
    >(&list_query)
    .bind(page_size as i32)
    .bind(offset)
    .fetch_all(db.pool())
    .await
    {
        Ok(rows) => rows
            .into_iter()
            .map(
                |(face_id, name, created_at, updated_at, is_active, metadata)| FaceListItem {
                    face_id,
                    name,
                    created_at: created_at.to_rfc3339(),
                    updated_at: updated_at.to_rfc3339(),
                    is_active,
                    metadata,
                },
            )
            .collect(),
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to list faces: {}", e),
            ))
        }
    };

    Ok(Json(FaceListResponse {
        success: true,
        message: format!("Found {} faces", total),
        faces,
        count: total,
        page,
        page_size,
    }))
}

async fn get_face_details(
    State(_state): State<crate::api::server::AppState>,
    Path(face_id): Path<String>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    let face_identities_table = schema::table_name("face_identities");
    let query = format!(
        r#"
        SELECT 
            face_id,
            name,
            embedding,
            attributes,
            metadata,
            created_at,
            updated_at,
            is_active
        FROM {}
        WHERE face_id = $1
    "#,
        face_identities_table
    );

    let face: Option<(
        String,
        Option<String>,
        Option<String>,
        Option<serde_json::Value>,
        Option<serde_json::Value>,
        chrono::DateTime<chrono::Utc>,
        chrono::DateTime<chrono::Utc>,
        bool,
    )> = match sqlx::query_as(&query)
        .bind(&face_id)
        .fetch_optional(db.pool())
        .await
    {
        Ok(face) => face,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to fetch face details: {}", e),
            ))
        }
    };

    match face {
        Some((
            face_id,
            name,
            embedding,
            attributes,
            metadata,
            created_at,
            updated_at,
            is_active,
        )) => {
            let response = serde_json::json!({
                "success": true,
                "face_id": face_id,
                "name": name,
                "has_embedding": embedding.is_some(),
                "attributes": attributes,
                "metadata": metadata,
                "created_at": created_at.to_rfc3339(),
                "updated_at": updated_at.to_rfc3339(),
                "is_active": is_active
            });

            Ok(Json(response))
        }
        None => Err((
            StatusCode::NOT_FOUND,
            format!("Face not found: {}", face_id),
        )),
    }
}

async fn delete_face(
    State(_state): State<crate::api::server::AppState>,
    Path(face_id): Path<String>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    // Soft delete by marking as inactive
    let face_identities_table = schema::table_name("face_identities");
    let query = format!(
        r#"
        UPDATE {}
        SET is_active = FALSE, updated_at = CURRENT_TIMESTAMP
        WHERE face_id = $1 AND is_active = TRUE
        RETURNING face_id, name
    "#,
        face_identities_table
    );

    let deleted: Option<(String, Option<String>)> = match sqlx::query_as(&query)
        .bind(&face_id)
        .fetch_optional(db.pool())
        .await
    {
        Ok(result) => result,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to delete face: {}", e),
            ))
        }
    };

    match deleted {
        Some((deleted_id, name)) => {
            let response = serde_json::json!({
                "success": true,
                "message": format!("Face '{}' deleted successfully", name.clone().unwrap_or_else(|| deleted_id.clone())),
                "face_id": deleted_id.clone()
            });

            Ok(Json(response))
        }
        None => Err((
            StatusCode::NOT_FOUND,
            format!("Face not found or already deleted: {}", face_id),
        )),
    }
}

async fn get_recognition_results(
    State(_state): State<crate::api::server::AppState>,
    Path(video_uuid): Path<String>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to connect to database: {}", e),
            ))
        }
    };

    let query = r#"
        SELECT 
            video_uuid,
            frame_count,
            fps,
            total_faces,
            recognized_faces,
            clusters_count,
            result_data,
            processing_time_secs,
            created_at
        FROM face_recognition_results
        WHERE video_uuid = $1
        ORDER BY created_at DESC
        LIMIT 1
    "#;

    let result: Option<(
        String,
        i64,
        f64,
        i32,
        i32,
        i32,
        serde_json::Value,
        Option<f64>,
        chrono::DateTime<chrono::Utc>,
    )> = match sqlx::query_as(query)
        .bind(&video_uuid)
        .fetch_optional(db.pool())
        .await
    {
        Ok(result) => result,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Failed to fetch recognition results: {}", e),
            ))
        }
    };

    match result {
        Some((
            video_uuid,
            frame_count,
            fps,
            total_faces,
            recognized_faces,
            clusters_count,
            result_data,
            processing_time_secs,
            created_at,
        )) => {
            let response = serde_json::json!({
                "success": true,
                "video_uuid": video_uuid,
                "frame_count": frame_count,
                "fps": fps,
                "total_faces": total_faces,
                "recognized_faces": recognized_faces,
                "clusters_count": clusters_count,
                "result_data": result_data,
                "processing_time_secs": processing_time_secs,
                "created_at": created_at.to_rfc3339()
            });

            Ok(Json(response))
        }
        None => Err((
            StatusCode::NOT_FOUND,
            format!("No recognition results found for video: {}", video_uuid),
        )),
    }
}

async fn store_recognition_results(
    db: &PostgresDb,
    video_uuid: &str,
    result: &FaceRecognitionResult,
) -> Result<(), anyhow::Error> {
    let total_faces = result.frames.iter().map(|f| f.faces.len()).sum::<usize>();
    let recognized_faces = result
        .frames
        .iter()
        .flat_map(|f| &f.faces)
        .filter(|face| face.identity.is_some())
        .count();

    let query = r#"
        INSERT INTO face_recognition_results (
            video_uuid,
            frame_count,
            fps,
            total_faces,
            recognized_faces,
            clusters_count,
            result_data
        ) VALUES ($1, $2, $3, $4, $5, $6, $7)
        ON CONFLICT (video_uuid) DO UPDATE SET
            frame_count = EXCLUDED.frame_count,
            fps = EXCLUDED.fps,
            total_faces = EXCLUDED.total_faces,
            recognized_faces = EXCLUDED.recognized_faces,
            clusters_count = EXCLUDED.clusters_count,
            result_data = EXCLUDED.result_data,
            updated_at = CURRENT_TIMESTAMP
    "#;

    sqlx::query(query)
        .bind(video_uuid)
        .bind(result.frame_count as i64)
        .bind(result.fps)
        .bind(total_faces as i32)
        .bind(recognized_faces as i32)
        .bind(result.face_clusters.len() as i32)
        .bind(serde_json::to_value(result)?)
        .execute(db.pool())
        .await?;

    // Store individual face detections
    for frame in &result.frames {
        for face in &frame.faces {
            if let Some(embedding) = &face.embedding {
                let embedding_str = format!(
                    "[{}]",
                    embedding
                        .iter()
                        .map(|v| v.to_string())
                        .collect::<Vec<_>>()
                        .join(",")
                );

                let insert_query = r#"
                    INSERT INTO face_detections (
                        video_uuid,
                        frame_number,
                        timestamp_secs,
                        face_id,
                        x,
                        y,
                        width,
                        height,
                        confidence,
                        embedding,
                        attributes,
                        identity_confidence,
                        cluster_id
                    ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10::vector, $11, $12, $13)
                    ON CONFLICT (video_uuid, frame_number, x, y, width, height) DO UPDATE SET
                        face_id = EXCLUDED.face_id,
                        confidence = EXCLUDED.confidence,
                        embedding = EXCLUDED.embedding,
                        attributes = EXCLUDED.attributes,
                        identity_confidence = EXCLUDED.identity_confidence,
                        cluster_id = EXCLUDED.cluster_id
                "#;

                let identity_confidence = face.identity.as_ref().map(|id| id.confidence as f64);
                let cluster_id = result
                    .face_clusters
                    .iter()
                    .find(|c| {
                        c.face_ids
                            .contains(&face.face_id.clone().unwrap_or_default())
                    })
                    .map(|c| c.cluster_id.clone());

                sqlx::query(insert_query)
                    .bind(video_uuid)
                    .bind(frame.frame as i64)
                    .bind(frame.timestamp)
                    .bind(face.face_id.as_deref())
                    .bind(face.x)
                    .bind(face.y)
                    .bind(face.width)
                    .bind(face.height)
                    .bind(face.confidence as f64)
                    .bind(&embedding_str)
                    .bind(serde_json::to_value(&face.attributes)?)
                    .bind(identity_confidence)
                    .bind(cluster_id)
                    .execute(db.pool())
                    .await?;
            }
        }
    }

    // Store face clusters
    for cluster in &result.face_clusters {
        let centroid = &cluster.centroid;
        let centroid_str = format!(
            "[{}]",
            centroid
                .iter()
                .map(|v: &f32| v.to_string())
                .collect::<Vec<_>>()
                .join(",")
        );

        let cluster_query = r#"
            INSERT INTO face_clusters (
                cluster_id,
                video_uuid,
                centroid,
                size,
                representative_face_id,
                metadata
            ) VALUES ($1, $2, $3::vector, $4, $5, $6)
            ON CONFLICT (cluster_id) DO UPDATE SET
                centroid = EXCLUDED.centroid,
                size = EXCLUDED.size,
                representative_face_id = EXCLUDED.representative_face_id,
                metadata = EXCLUDED.metadata
        "#;

        sqlx::query(cluster_query)
            .bind(&cluster.cluster_id)
            .bind(video_uuid)
            .bind(&centroid_str)
            .bind(cluster.size as i32)
            .bind(cluster.representative_face_id.as_deref())
            .bind(&cluster.metadata)
            .execute(db.pool())
            .await?;
    }

    Ok(())
}
