<?php

namespace DigitalApps\PaymentsForAdyen;

defined('ABSPATH') || exit;

/** Stable identifiers and order metadata for retry-safe Adyen operations. */
final class Adyen_Operation
{
	const META_KEY = '_digitalapps_payments_for_adyen_operations';

	/**
	 * Get or create a persistent idempotency key for a logical order operation.
	 *
	 * @param \WC_Order $order WooCommerce order.
	 * @param string    $operation_id Stable logical operation identifier.
	 * @return string
	 */
	public static function key_for_order($order, $operation_id)
	{
		$operation_id = self::normalize_operation_id($operation_id);
		$operations = $order->get_meta(self::META_KEY, true);
		if (!is_array($operations)) {
			$operations = [];
		}

		if (empty($operations[$operation_id]['idempotencyKey'])) {
			$operations[$operation_id] = [
				'idempotencyKey' => wp_generate_uuid4(),
				'status' => 'created',
				'updatedAt' => gmdate('c'),
			];
			$order->update_meta_data(self::META_KEY, $operations);
			$order->save();
		}

		return (string) $operations[$operation_id]['idempotencyKey'];
	}

	/**
	 * Mark an order operation for duplicate-operation guards and reconciliation.
	 *
	 * @param \WC_Order $order WooCommerce order.
	 * @param string    $operation_id Logical operation identifier.
	 * @param string    $status Operation status.
	 * @param array     $data Non-secret operational fields.
	 * @return void
	 */
	public static function mark($order, $operation_id, $status, array $data = [])
	{
		$operation_id = self::normalize_operation_id($operation_id);
		$operations = $order->get_meta(self::META_KEY, true);
		if (!is_array($operations)) {
			$operations = [];
		}
		$existing = is_array($operations[$operation_id] ?? null) ? $operations[$operation_id] : [];
		$operations[$operation_id] = array_merge($existing, $data, [
			'status' => sanitize_key($status),
			'updatedAt' => gmdate('c'),
		]);
		$order->update_meta_data(self::META_KEY, $operations);
		$order->save();
	}

	/**
	 * Return one tracked logical operation.
	 *
	 * @param \WC_Order $order WooCommerce order.
	 * @param string    $operation_id Logical operation identifier.
	 * @return array
	 */
	public static function get($order, $operation_id)
	{
		$operations = $order->get_meta(self::META_KEY, true);
		$operation_id = self::normalize_operation_id($operation_id);
		return is_array($operations) && is_array($operations[$operation_id] ?? null)
			? $operations[$operation_id]
			: [];
	}

	/**
	 * Create a bounded fallback key for shared callers that cannot supply an order.
	 *
	 * @param string $operation_id Logical operation identifier.
	 * @return string
	 */
	public static function deterministic_key($operation_id)
	{
		return substr(hash_hmac('sha256', self::normalize_operation_id($operation_id), wp_salt('nonce')), 0, 64);
	}

	private static function normalize_operation_id($operation_id)
	{
		$normalized = preg_replace('/[^A-Za-z0-9._:-]/', '-', (string) $operation_id);
		return '' !== $normalized ? substr($normalized, 0, 160) : 'unspecified';
	}
}
