// Personlig arbeidsflate — oppgave 19.6
//
// GET /my/workspace — finn eller opprett brukerens personlige workspace-node.
//
// Hvert bruker-node har én workspace-node (node_kind='workspace') koblet via
// en owner-edge. Ved første kall opprettes noden automatisk.
//
// Ref: docs/retninger/arbeidsflaten.md § "Tre lag"

use axum::extract::State;
use axum::http::StatusCode;
use axum::Json;
use serde::Serialize;
use uuid::Uuid;

use crate::auth::AuthUser;
use crate::AppState;

#[derive(Serialize)]
pub struct WorkspaceResponse {
    pub node_id: Uuid,
    pub title: String,
    pub metadata: serde_json::Value,
    pub created: bool,
}

#[derive(sqlx::FromRow)]
struct WorkspaceRow {
    id: Uuid,
    title: String,
    metadata: serde_json::Value,
}

/// GET /my/workspace — finn eller opprett brukerens personlige workspace.
pub async fn my_workspace(
    State(state): State<AppState>,
    user: AuthUser,
) -> Result<Json<WorkspaceResponse>, (StatusCode, String)> {
    // Søk etter eksisterende workspace-node der brukeren er eier
    let existing = sqlx::query_as::<_, WorkspaceRow>(
        r#"
        SELECT n.id, n.title, n.metadata
        FROM nodes n
        INNER JOIN edges e ON e.target_id = n.id
        WHERE e.source_id = $1
          AND e.edge_type = 'owner'
          AND n.node_kind = 'workspace'
        LIMIT 1
        "#,
    )
    .bind(user.node_id)
    .fetch_optional(&state.db)
    .await
    .map_err(|e| {
        tracing::error!("PG-feil ved workspace-oppslag: {e}");
        (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
    })?;

    if let Some(row) = existing {
        return Ok(Json(WorkspaceResponse {
            node_id: row.id,
            title: row.title,
            metadata: row.metadata,
            created: false,
        }));
    }

    // Ingen workspace funnet — opprett ny
    let node_id = Uuid::now_v7();
    let title = "Min arbeidsflate".to_string();
    let metadata = serde_json::json!({
        "workspace_layout": {
            "panels": []
        }
    });

    // Skriv workspace-node til PG
    sqlx::query(
        r#"INSERT INTO nodes (id, node_kind, title, content, visibility, metadata, created_by)
           VALUES ($1, 'workspace', $2, '', 'hidden'::visibility, $3, $4)
           ON CONFLICT (id) DO NOTHING"#,
    )
    .bind(node_id)
    .bind(&title)
    .bind(&metadata)
    .bind(user.node_id)
    .execute(&state.db)
    .await
    .map_err(|e| {
        tracing::error!("PG-feil ved workspace-opprettelse: {e}");
        (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
    })?;

    // Opprett owner-edge med recompute_access
    let edge_id = Uuid::now_v7();

    let mut tx = state.db.begin().await.map_err(|e| {
        tracing::error!("PG begin: {e}");
        (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
    })?;

    sqlx::query(
        r#"INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by)
           VALUES ($1, $2, $3, 'owner', '{}', false, $2)
           ON CONFLICT (id) DO NOTHING"#,
    )
    .bind(edge_id)
    .bind(user.node_id)
    .bind(node_id)
    .execute(&mut *tx)
    .await
    .map_err(|e| {
        tracing::error!("PG-feil ved workspace owner-edge: {e}");
        (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
    })?;

    sqlx::query("SELECT recompute_access($1, $2, 'owner'::access_level, $3)")
        .bind(user.node_id)
        .bind(node_id)
        .bind(edge_id)
        .execute(&mut *tx)
        .await
        .map_err(|e| {
            tracing::error!("recompute_access: {e}");
            (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
        })?;

    tx.commit().await.map_err(|e| {
        tracing::error!("PG commit: {e}");
        (StatusCode::INTERNAL_SERVER_ERROR, "Databasefeil".to_string())
    })?;

    tracing::info!(
        node_id = %node_id,
        user_id = %user.node_id,
        "Personlig workspace opprettet"
    );

    Ok(Json(WorkspaceResponse {
        node_id,
        title,
        metadata,
        created: true,
    }))
}
