// describe_image — AI-beskrivelse av bilder via synops-ai CLI.
//
// Jobbtype: "describe_image"
// Payload: { "media_node_id", "cas_hash", "mime" }
//
// Flyten:
// 1. Sender bildefilen (CAS-sti) til synops-ai prompt --image
// 2. synops-ai sender multimodal melding til LLM via LiteLLM
// 3. Oppdaterer media-nodens metadata med description-feltet
//
// Ref: docs/retninger/unix_filosofi.md, oppgave 29.1

use sqlx::PgPool;
use uuid::Uuid;

use crate::cas::CasStore;
use crate::jobs::JobRow;

/// Håndterer describe_image-jobb.
///
/// Sender bildet til synops-ai for beskrivelse via vision-modell,
/// og lagrer resultatet i media-nodens metadata.
pub async fn handle_describe_image(
    job: &JobRow,
    db: &PgPool,
    cas: &CasStore,
) -> Result<serde_json::Value, String> {
    let media_node_id: Uuid = job.payload["media_node_id"]
        .as_str()
        .and_then(|s| s.parse().ok())
        .ok_or("Mangler gyldig 'media_node_id' i payload")?;

    let cas_hash = job.payload["cas_hash"]
        .as_str()
        .ok_or("Mangler 'cas_hash' i payload")?;

    let mime = job.payload["mime"]
        .as_str()
        .unwrap_or("image/png");

    // Verifiser at bildet finnes i CAS
    let cas_path = cas.path_for(cas_hash);
    if !cas_path.exists() {
        return Err(format!("Bilde ikke funnet i CAS: {cas_hash}"));
    }

    let bin = std::env::var("SYNOPS_AI_BIN")
        .unwrap_or_else(|_| "synops-ai".to_string());

    tracing::info!(
        media_node_id = %media_node_id,
        cas_hash,
        "Sender bilde til AI for beskrivelse"
    );

    let output = tokio::process::Command::new(&bin)
        .arg("prompt")
        .arg("--prompt")
        .arg("Beskriv dette bildet kort og konsist på norsk. Fokuser på innholdet, ikke formatet. Maks 2-3 setninger.")
        .arg("--image")
        .arg(cas_path.to_str().unwrap_or(""))
        .arg("--image-mime")
        .arg(mime)
        .arg("--job-type")
        .arg("describe_image")
        .arg("--temperature")
        .arg("0.3")
        .output()
        .await
        .map_err(|e| format!("Kunne ikke starte {bin}: {e}"))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(format!("synops-ai feilet: {stderr}"));
    }

    let description = String::from_utf8_lossy(&output.stdout).trim().to_string();

    if description.is_empty() {
        return Err("synops-ai returnerte tom beskrivelse".into());
    }

    tracing::info!(
        media_node_id = %media_node_id,
        description_len = description.len(),
        "Bildebeskrivelse mottatt fra AI"
    );

    // Oppdater media-nodens metadata med description
    sqlx::query(
        r#"UPDATE nodes
           SET metadata = metadata || jsonb_build_object('description', $2::text),
               updated_at = now()
           WHERE id = $1"#,
    )
    .bind(media_node_id)
    .bind(&description)
    .execute(db)
    .await
    .map_err(|e| format!("Kunne ikke oppdatere media-node med beskrivelse: {e}"))?;

    // PG NOTIFY-trigger på nodes-tabellen sender sanntidsoppdatering automatisk.

    Ok(serde_json::json!({
        "media_node_id": media_node_id.to_string(),
        "description": description,
    }))
}
