<?php
/**
 * Configurable Trigger - Generic Executor
 *
 * Implements TriggerHandler using TriggerDefinition configuration.
 * Extends AbstractTrigger to inherit workflow execution logic.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Triggers\Configuration;

use Sequensy\Engine\ExecutionGuard;
use Sequensy\Engine\FilterEvaluator;
use Sequensy\Triggers\AbstractTrigger;
use Sequensy\Storage\WorkflowStorage;
use Sequensy\Storage\ActivityLogger;

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Class ConfigurableTrigger
 *
 * Generic trigger executor that interprets TriggerDefinition configuration.
 * Handles hook registration, event handling, and context building.
 */
final class ConfigurableTrigger extends AbstractTrigger {

	/**
	 * The trigger definition.
	 *
	 * @var TriggerDefinition
	 */
	private TriggerDefinition $definition;

	/**
	 * Constructor.
	 *
	 * @param TriggerDefinition $definition       The trigger definition.
	 * @param WorkflowStorage   $storage          Workflow storage instance.
	 * @param object            $queue_manager    Queue manager instance.
	 * @param ActivityLogger    $logger           Activity logger instance.
	 * @param FilterEvaluator   $filter_evaluator Filter evaluator instance.
	 * @param ExecutionGuard    $execution_guard  Execution guard instance.
	 */
	public function __construct(
		TriggerDefinition $definition,
		WorkflowStorage $storage,
		object $queue_manager,
		ActivityLogger $logger,
		FilterEvaluator $filter_evaluator,
		ExecutionGuard $execution_guard
	) {
		parent::__construct( $storage, $queue_manager, $logger, $filter_evaluator, $execution_guard );
		$this->definition = $definition;
	}

	/**
	 * Get trigger type identifier.
	 *
	 * @return string Trigger type.
	 */
	public function get_type(): string {
		return $this->definition->type;
	}

	/**
	 * Get trigger display label.
	 *
	 * @return string Trigger label.
	 */
	public function get_label(): string {
		return $this->definition->label;
	}

	/**
	 * Get trigger description.
	 *
	 * @return string Trigger description.
	 */
	public function get_description(): string {
		return $this->definition->description;
	}

	/**
	 * Get the integration this trigger belongs to.
	 *
	 * @return string|null Integration slug or null for WordPress core.
	 */
	public function get_integration(): ?string {
		return $this->definition->integration;
	}

	/**
	 * Get available data fields for this trigger.
	 *
	 * @return array Array of field definition objects.
	 */
	public function get_available_fields(): array {
		$fields = $this->definition->get_available_fields();

		// Add standard trigger fields if not already present.
		$has_trigger_type = false;
		$has_trigger_time = false;

		foreach ( $fields as $field ) {
			if ( 'trigger_type' === ( $field['name'] ?? '' ) ) {
				$has_trigger_type = true;
			}
			if ( 'trigger_time' === ( $field['name'] ?? '' ) ) {
				$has_trigger_time = true;
			}
		}

		if ( ! $has_trigger_type ) {
			$fields[] = array(
				'name'        => 'trigger_type',
				'type'        => 'string',
				'description' => 'Type of trigger that fired',
				'example'     => $this->definition->type,
			);
		}

		if ( ! $has_trigger_time ) {
			$fields[] = array(
				'name'        => 'trigger_time',
				'type'        => 'datetime',
				'description' => 'Timestamp when the trigger fired',
				'example'     => '2024-01-15 10:30:05',
			);
		}

		return $fields;
	}

	/**
	 * Register trigger hooks.
	 *
	 * Hooks into the WordPress action defined in the definition.
	 */
	public function register(): void {
		// Check should_fire condition if defined.
		if ( $this->definition->has_condition() && ! $this->definition->should_fire() ) {
			return;
		}

		add_action(
			$this->definition->hook,
			array( $this, 'handle_event' ),
			$this->definition->priority,
			$this->definition->accepted_args
		);
	}

	/**
	 * Handle the WordPress event.
	 *
	 * Builds context from hook arguments and executes matching workflows.
	 *
	 * @param mixed ...$args Hook arguments.
	 */
	public function handle_event( ...$args ): void {
		// Build context using the definition's closure.
		$context = $this->definition->build_context( ...$args );

		// If context builder returns null, skip execution.
		if ( null === $context ) {
			return;
		}

		// Add trigger metadata if not present.
		if ( ! isset( $context['trigger_type'] ) ) {
			$context['trigger_type'] = $this->definition->type;
		}
		if ( ! isset( $context['trigger_time'] ) ) {
			$context['trigger_time'] = current_time( 'mysql' );
		}

		// Execute matching workflows (inherited from AbstractTrigger).
		$this->execute_matching_workflows( $context );
	}

	/**
	 * Get the underlying definition.
	 *
	 * @return TriggerDefinition The definition.
	 */
	public function get_definition(): TriggerDefinition {
		return $this->definition;
	}
}
