<?php

/**
 * @file
 * Post-update hooks for the flowdrop_workflow module.
 */

declare(strict_types=1);

use Drupal\flowdrop_workflow\Entity\FlowDropWorkflow;

/**
 * Materialise schema-related defaults on existing workflow entities.
 *
 * Adds five new config properties — input_ports, output_ports,
 * parameter_schema, output_schema, schema_version — with their declared
 * defaults so existing config doesn't trip "config schema mismatch" warnings
 * or produce misleading config:export diffs.
 *
 * Each entity is saved with setSyncing(TRUE) so preSave() skips the new
 * snapshot rebuild path — no plugin lookups, no version bumps during the
 * upgrade itself.
 *
 * @param-out array $sandbox
 */
function flowdrop_workflow_post_update_add_schema_fields(?array &$sandbox = NULL): void {
  $storage = \Drupal::entityTypeManager()->getStorage('flowdrop_workflow');

  if (!isset($sandbox['ids'])) {
    $sandbox['ids'] = $storage->getQuery()->accessCheck(FALSE)->execute();
    $sandbox['total'] = count($sandbox['ids']);
    $sandbox['progress'] = 0;
  }

  $batch = array_splice($sandbox['ids'], 0, 25);
  foreach ($batch as $id) {
    $entity = $storage->load($id);
    if (!$entity instanceof FlowDropWorkflow) {
      continue;
    }
    $entity->setInputPorts(NULL);
    $entity->setOutputPorts(NULL);
    $entity->setSyncing(TRUE);
    $entity->save();
    $sandbox['progress']++;
  }

  $sandbox['#finished'] = $sandbox['total'] === 0
    ? 1
    : ($sandbox['progress'] / $sandbox['total']);
}

/**
 * Migrate stored nodes to the slim node-identity format.
 *
 * Two storage-format changes land together:
 *  - data.nodeId is removed (it only ever duplicated the top-level node id).
 *  - the node-type anchor data.metadata.id is renamed to
 *    data.metadata.node_type_id (matching the engine's node_type_id vocabulary
 *    and disambiguating it from the top-level node id).
 *
 * Unlike the schema-fields backfill above, this hook saves each workflow
 * WITHOUT setSyncing(TRUE) on purpose: FlowDropWorkflow::preSave() →
 * slimNodesForStorage() performs the rename-and-drop, reading the legacy
 * `metadata.id` and writing `metadata.node_type_id`. A plain resave is all the
 * migration needs. Idempotent — an already-slim workflow resaves unchanged.
 * Batched 25 per pass.
 *
 * @param-out array $sandbox
 */
function flowdrop_workflow_post_update_slim_node_identity(?array &$sandbox = NULL): void {
  $storage = \Drupal::entityTypeManager()->getStorage('flowdrop_workflow');

  if (!isset($sandbox['ids'])) {
    $sandbox['ids'] = $storage->getQuery()->accessCheck(FALSE)->execute();
    $sandbox['total'] = count($sandbox['ids']);
    $sandbox['progress'] = 0;
  }

  $batch = array_splice($sandbox['ids'], 0, 25);
  foreach ($batch as $id) {
    $entity = $storage->load($id);
    if (!$entity instanceof FlowDropWorkflow) {
      continue;
    }
    // No setSyncing(): let preSave slim and rename the stored nodes.
    $entity->save();
    $sandbox['progress']++;
  }

  $sandbox['#finished'] = $sandbox['total'] === 0
    ? 1
    : ($sandbox['progress'] / $sandbox['total']);
}
