<?php

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

declare(strict_types=1);

use Drupal\flowdrop_session\Constants\MessageRole;
use Drupal\flowdrop_session\Entity\FlowDropSessionMessageInterface;

/**
 * Delete `interrupt_request` session messages for linked interrupts.
 *
 * Linked interrupts (parent WorkflowExecution placeholders gated on a
 * sub-pipeline sentinel) used to emit a no-op "Sub-workflow … running
 * asynchronously" bubble into the parent's session stream. The sub
 * workflow's own messages already populate the stream and carry the
 * actual HITL prompt, so the placeholder is pure noise.
 *
 * Walks every `interrupt_request` message and deletes those whose
 * referenced interrupt has a non-empty `linked_interrupt_id`. Batched
 * 100 at a time so large installations don't OOM.
 *
 * @param-out array $sandbox
 */
function flowdrop_session_post_update_clean_linked_interrupt_request_messages(?array &$sandbox = NULL): void {
  $messageStorage = \Drupal::entityTypeManager()->getStorage('flowdrop_session_message');
  $interruptStorage = \Drupal::entityTypeManager()->getStorage('flowdrop_interrupt');

  if (!isset($sandbox['ids'])) {
    // Pre-filter on the metadata field is tricky (JSON blob), so we walk
    // everything once. Cheap enough for an install-time backfill.
    $sandbox['ids'] = $messageStorage->getQuery()
      ->condition('role', MessageRole::SYSTEM)
      ->accessCheck(FALSE)
      ->execute();
    $sandbox['total'] = count($sandbox['ids']);
    $sandbox['progress'] = 0;
    $sandbox['deleted'] = 0;
  }

  $batch = array_splice($sandbox['ids'], 0, 100);
  foreach ($batch as $id) {
    $sandbox['progress']++;
    $message = $messageStorage->load($id);
    if (!$message instanceof FlowDropSessionMessageInterface) {
      continue;
    }
    if (!method_exists($message, 'getMessageMetadata')) {
      continue;
    }
    $metadata = $message->getMessageMetadata();
    if (!is_array($metadata) || ($metadata['type'] ?? NULL) !== 'interrupt_request') {
      continue;
    }
    $interruptId = $metadata['interrupt_id'] ?? NULL;
    if (!is_string($interruptId) || $interruptId === '') {
      continue;
    }
    $loaded = $interruptStorage->loadByProperties(['uuid' => $interruptId]);
    $interrupt = $loaded ? reset($loaded) : NULL;
    if ($interrupt === NULL) {
      continue;
    }
    if (!method_exists($interrupt, 'getLinkedInterruptId')) {
      continue;
    }
    $linked = $interrupt->getLinkedInterruptId();
    if (!is_string($linked) || $linked === '') {
      continue;
    }
    $message->delete();
    $sandbox['deleted']++;
  }

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

  if ($sandbox['#finished'] >= 1) {
    \Drupal::messenger()->addStatus(t('Deleted @count noise interrupt_request messages for linked interrupts.', [
      '@count' => $sandbox['deleted'],
    ]));
  }
}
