<?php

declare(strict_types=1);

namespace Drupal\flowdrop_workflow\Hook;

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\flowdrop_workflow\FlowDropWorkflowInterface;
use Drupal\flowdrop_workflow\Service\WorkflowSchemaSnapshotterInterface;
use Psr\Log\LoggerInterface;

/**
 * Hook implementations for the flowdrop_workflow module.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class Hooks {

  use StringTranslationTrait;

  /**
   * Constructs a new Hooks object.
   *
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger channel.
   * @param \Drupal\flowdrop_workflow\Service\WorkflowSchemaSnapshotterInterface $snapshotter
   *   Rebuilds and versions the workflow's schema snapshot on save.
   */
  public function __construct(
    protected readonly LoggerInterface $logger,
    protected readonly WorkflowSchemaSnapshotterInterface $snapshotter,
  ) {}

  /**
   * Implements hook_ENTITY_TYPE_presave() for flowdrop_workflow.
   *
   * Delegates the schema-snapshot rebuild + version bump to the snapshotter
   * service. The entity itself stays free of service lookups; this hook is
   * the wired-in entry point that runs on every save (form, programmatic,
   * drush) — config-sync saves short-circuit inside the snapshotter via the
   * entity's isSyncing() flag.
   */
  #[Hook('flowdrop_workflow_presave')]
  public function workflowPresave(EntityInterface $entity): void {
    if (!$entity instanceof FlowDropWorkflowInterface) {
      return;
    }
    $original = $entity->original ?? NULL;
    $this->snapshotter->rebuildIfNeeded(
      $entity,
      $original instanceof FlowDropWorkflowInterface ? $original : NULL,
      $entity->isSchemaRebuildForced(),
    );
  }

  /**
   * Implements hook_ENTITY_TYPE_insert() for flowdrop_workflow.
   *
   * Invalidates the FlowDropNodeProcessor plugin cache so the workflow:<id>
   * derivative for the new workflow shows up immediately.
   */
  #[Hook('flowdrop_workflow_insert')]
  public function workflowInsert(EntityInterface $entity): void {
    if ($entity instanceof FlowDropWorkflowInterface) {
      $this->clearWorkflowDerivativeCache();
    }
  }

  /**
   * Implements hook_ENTITY_TYPE_update() for flowdrop_workflow.
   */
  #[Hook('flowdrop_workflow_update')]
  public function workflowUpdate(EntityInterface $entity): void {
    if ($entity instanceof FlowDropWorkflowInterface) {
      $this->clearWorkflowDerivativeCache();
    }
  }

  /**
   * Implements hook_ENTITY_TYPE_delete() for flowdrop_workflow.
   */
  #[Hook('flowdrop_workflow_delete')]
  public function workflowDelete(EntityInterface $entity): void {
    if ($entity instanceof FlowDropWorkflowInterface) {
      $this->clearWorkflowDerivativeCache();
    }
  }

  /**
   * Clears the FlowDropNodeProcessor plugin definitions cache.
   *
   * Workflow derivative plugins (workflow:<id>) are generated by
   * WorkflowNodeDeriver from flowdrop_workflow config entities. The plugin
   * manager caches definitions, so workflow saves/deletes must explicitly
   * invalidate it.
   */
  protected function clearWorkflowDerivativeCache(): void {
    try {
      // @phpstan-ignore globalDrupalDependencyInjection.useDependencyInjection (Avoid an injection cycle with the plugin manager that derives definitions from this entity type.)
      \Drupal::service('flowdrop.node_processor_plugin_manager')->clearCachedDefinitions();
    }
    catch (\Throwable $e) {
      $this->logger->warning('Failed to clear FlowDropNodeProcessor plugin cache: @message', [
        '@message' => $e->getMessage(),
      ]);
    }
  }

}
