<?php
/**
 * AbstractTrigger — base class for all Autopilot triggers.
 *
 * v1.3 additions:
 *   get_sentence()      — short natural-language clause for the story bar.
 *   get_test_data()     — sample payload for the Test Play button.
 *   is_still_valid()    — DeferredStateCheck: re-evaluate before delayed action fires.
 *
 * @package CartCue
 */

namespace CartCue\Triggers;

use CartCue\Contracts\TriggerInterface;
use CartCue\Plugin;

defined( 'ABSPATH' ) || exit;

abstract class AbstractTrigger implements TriggerInterface {

	protected Plugin $plugin;

	public function __construct( Plugin $plugin ) {
		$this->plugin = $plugin;
	}

	/** Unique slug used to reference this trigger in play config. */
	abstract public function get_slug(): string;

	/** Human-readable label shown in dropdowns. */
	abstract public function get_label(): string;

	/**
	 * Short natural-language clause completing the sentence
	 * "When [sentence]...".
	 *
	 * Examples:
	 *   "a customer pays for an order"
	 *   "someone leaves items in their cart"
	 *
	 * Used to build the live story preview in the play editor.
	 */
	public function get_sentence(): string {
		return strtolower( $this->get_label() );
	}

	/** Longer description shown below the trigger label. */
	public function get_description(): string {
		return '';
	}

	/**
	 * Register all WordPress/WooCommerce hooks needed by this trigger.
	 * Called once during Plugin::init().
	 */
	abstract public function register_hooks(): void;

	/**
	 * Trigger-specific settings fields shown in the play editor.
	 *
	 * @return array  Array of field defs: 'key', 'label', 'type', 'default', ['options'].
	 */
	public function get_settings_fields(): array {
		return [];
	}

	/**
	 * Return representative sample context data for this trigger.
	 * Used by the Test Play button to fire a play with realistic data
	 * without needing a real customer event.
	 *
	 * Always include '_is_test' => true so actions can modify their
	 * behaviour (e.g. prefix email subjects with [TEST]).
	 *
	 * @return array
	 */
	public function get_test_data(): array {
		return [
			'trigger'        => $this->get_slug(),
			'customer_email' => get_option( 'admin_email', '' ),
			'_is_test'       => true,
		];
	}

	/**
	 * DeferredStateCheck — called before a delayed play fires.
	 *
	 * Triggers that support deferred re-validation should override this.
	 * Default: always valid (no recheck, same behaviour as v1.2).
	 *
	 * @param array $data  Original trigger context saved when the play was queued.
	 * @return bool  True = still valid, proceed. False = skip this run.
	 */
	public function is_still_valid( array $data ): bool {
		return true;
	}

	/**
	 * Whether this trigger supports deferred state rechecking.
	 * Exposed so the editor can show the "Re-verify before sending" checkbox.
	 */
	public function supports_recheck(): bool {
		return false;
	}

	/** Whether this trigger appears in the play editor trigger picker. */
	public function show_in_picker(): bool {
		return true;
	}

	/**
	 * Fire all active workflows registered to this trigger.
	 *
	 * @param array $data  Context data (order_id, customer_email, etc.)
	 */
	protected function fire( array $data ): void {
		$this->plugin->runner->fire_trigger( $this->get_slug(), $this->normalize_payload( $data ) );
	}

	/**
	 * Normalized trigger payload contract for all workflows.
	 *
	 * @param array<string,mixed> $data Raw trigger payload.
	 * @return array<string,mixed>
	 */
	protected function normalize_payload( array $data ): array {
		$normalized                     = $data;
		$normalized['trigger']          = $this->get_slug();
		$normalized['triggered_at']     = (string) ( $normalized['triggered_at'] ?? current_time( 'mysql' ) );
		$normalized['customer_email']   = sanitize_email( $normalized['customer_email'] ?? '' );
		$normalized['customer_id']      = isset( $normalized['customer_id'] ) ? absint( $normalized['customer_id'] ) : 0;
		$normalized['order_id']         = isset( $normalized['order_id'] ) ? absint( $normalized['order_id'] ) : 0;
		$normalized['cart_hash']        = isset( $normalized['cart_hash'] ) ? sanitize_text_field( (string) $normalized['cart_hash'] ) : '';

		return $normalized;
	}
}
