<?php
/**
 * Velocity_Recorder — persists submission / decline / gate-block events to
 * the velocity_events table. Subscribed to trustlens/gate_evaluated to record
 * every gate pass. Called directly by decline-hooks (Task 3) for
 * payment-decline events.
 *
 * @package TrustLens
 * @since   1.2.2
 */

defined( 'ABSPATH' ) || exit;

class TrustLens_Velocity_Recorder {

	public const EVENT_SUBMISSION = 'submission';
	public const EVENT_DECLINE    = 'decline';
	public const EVENT_GATE_BLOCK = 'gate_block';

	public function register_hooks(): void {
		add_action( 'trustlens/gate_evaluated', array( $this, 'on_gate_evaluated' ), 10, 2 );
	}

	public function on_gate_evaluated( TrustLens_Gate_Context $ctx, ?TrustLens_Gate_Block $block ): void {
		// Only true checkout submissions count as a "submission" velocity event.
		// Cart writes (add-item, update-item, apply-coupon, etc.) run through
		// the gate so broader rules like the email blocklist can fire, but they
		// are NOT payment attempts — counting them as such inflates the
		// per-fingerprint submission counter and causes legitimate shoppers to
		// self-block by interacting with a reactive Blocks cart.
		if ( TrustLens_Gate_Context::INTENT_CHECKOUT_SUBMIT === $ctx->intent ) {
			$this->record_submission( $ctx );
		}

		// A gate block on either intent IS worth recording — it is the audit
		// trail for "we stopped this request" and includes blocked-customer
		// cart attempts. The detector does not count gate_block rows toward
		// the velocity threshold, so this does not feed the bug above.
		if ( $block instanceof TrustLens_Gate_Block ) {
			$this->record_gate_block( $ctx, $block );
		}
	}

	public function record_submission( TrustLens_Gate_Context $ctx ): void {
		$this->insert(
			$ctx->fingerprint_hash,
			self::EVENT_SUBMISSION,
			$ctx->ip,
			$ctx->email,
			null,
			null
		);
	}

	public function record_decline( string $fingerprint_hash, string $decline_code, ?int $order_id ): void {
		$this->insert(
			$fingerprint_hash,
			self::EVENT_DECLINE,
			null,
			null,
			$decline_code,
			$order_id
		);
	}

	public function record_gate_block( TrustLens_Gate_Context $ctx, TrustLens_Gate_Block $block ): void {
		$this->insert(
			$ctx->fingerprint_hash,
			self::EVENT_GATE_BLOCK,
			$ctx->ip,
			$ctx->email,
			$block->reason_code,
			null
		);
	}

	private function insert(
		string $fingerprint_hash,
		string $event_type,
		?string $ip,
		?string $email,
		?string $decline_code,
		?int $order_id
	): void {
		global $wpdb;
		$table = $wpdb->prefix . 'trustlens_velocity_events';

		$email_hash = null;
		if ( $email && function_exists( 'wstl_get_email_hash' ) ) {
			$email_hash = wstl_get_email_hash( $email );
		}

		$packed_ip = null;
		if ( $ip ) {
			$packed = @inet_pton( $ip );
			$packed_ip = false === $packed ? null : $packed;
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Insert into a custom event-log table; table name from $wpdb->prefix.
		$wpdb->insert(
			$table,
			array(
				'fingerprint_hash' => $fingerprint_hash,
				'event_type'       => $event_type,
				'ip'               => $packed_ip,
				'email_hash'       => $email_hash,
				'decline_code'     => $decline_code,
				'order_id'         => $order_id,
				'created_at'       => current_time( 'mysql', true ),
			),
			array( '%s', '%s', '%s', '%s', '%s', '%d', '%s' )
		);
	}
}
