<?php
/**
 * WooCommerce API integration.
 *
 * Exposes the estimated delivery on the WooCommerce REST API (products,
 * product variations and orders) and the Store API (Blocks cart), so headless
 * and app front-ends can read the estimate.
 *
 * @package EstimatedDeliveryDate
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class EDFW_WC_API
 *
 * @since 1.0.0
 */
class EDFW_WC_API {

	/**
	 * Singleton instance.
	 *
	 * @var EDFW_WC_API|null
	 */
	private static $instance = null;

	/**
	 * Get instance.
	 *
	 * @since 1.0.0
	 * @return EDFW_WC_API
	 */
	public static function instance(): EDFW_WC_API {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Hook up REST and Store API extensions.
	 *
	 * @since 1.0.0
	 */
	private function __construct() {
		add_action( 'rest_api_init', array( $this, 'register_rest_fields' ) );
		add_action( 'woocommerce_blocks_loaded', array( $this, 'register_store_api' ) );
	}

	/**
	 * Register the `edfw_estimated_delivery` field on products, variations and orders.
	 *
	 * @since 1.0.0
	 */
	public function register_rest_fields(): void {
		foreach ( array( 'product', 'product_variation' ) as $type ) {
			register_rest_field(
				$type,
				'edfw_estimated_delivery',
				array(
					'get_callback' => array( $this, 'get_product_estimate' ),
					'schema'       => $this->product_schema(),
				)
			);
		}

		register_rest_field(
			'shop_order',
			'edfw_estimated_delivery',
			array(
				'get_callback' => array( $this, 'get_order_estimate' ),
				'schema'       => array(
					'description' => __( 'Estimated delivery captured for each order line item.', 'wpactpro-estimated-delivery-date' ),
					'type'        => 'array',
					'context'     => array( 'view', 'edit' ),
					'readonly'    => true,
				),
			)
		);
	}

	/**
	 * Product / variation REST field callback.
	 *
	 * @since 1.0.0
	 * @param array $item_data Response data (contains the resource `id`).
	 * @return array|null
	 */
	public function get_product_estimate( $item_data ) {
		$product = wc_get_product( $item_data['id'] ?? 0 );
		if ( ! $product ) {
			return null;
		}
		$data = EDFW_Frontend::instance()->get_estimate_data( $product );
		return empty( $data ) ? null : $data;
	}

	/**
	 * Order REST field callback: the estimate stored on each line item.
	 *
	 * @since 1.0.0
	 * @param array $item_data Response data (contains the order `id`).
	 * @return array<int, array<string, mixed>>
	 */
	public function get_order_estimate( $item_data ) {
		$order = wc_get_order( $item_data['id'] ?? 0 );
		if ( ! $order ) {
			return array();
		}
		$out = array();
		foreach ( $order->get_items() as $item_id => $item ) {
			$text = $item->get_meta( '_edfw_delivery' );
			if ( '' !== $text ) {
				$out[] = array(
					'line_item_id' => (int) $item_id,
					'product_id'   => (int) $item->get_product_id(),
					'text'         => (string) $text,
				);
			}
		}
		return $out;
	}

	/**
	 * Extend the Store API cart line items with the estimate, so the block-based
	 * cart/checkout and headless clients can read it.
	 *
	 * @since 1.0.0
	 */
	public function register_store_api(): void {
		if ( ! function_exists( 'woocommerce_store_api_register_endpoint_data' )
			|| ! class_exists( '\Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema' ) ) {
			return;
		}

		woocommerce_store_api_register_endpoint_data(
			array(
				'endpoint'        => \Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema::IDENTIFIER,
				'namespace'       => 'edfw',
				'data_callback'   => array( $this, 'store_api_cart_item_data' ),
				'schema_callback' => array( $this, 'store_api_cart_item_schema' ),
				'schema_type'     => ARRAY_A,
			)
		);
	}

	/**
	 * Store API cart item data callback.
	 *
	 * @since 1.0.0
	 * @param array $cart_item Cart item.
	 * @return array<string, mixed>
	 */
	public function store_api_cart_item_data( $cart_item ): array {
		$product = $cart_item['data'] ?? null;
		$data    = $product ? EDFW_Frontend::instance()->get_estimate_data( $product ) : array();
		return array( 'estimate' => empty( $data ) ? null : $data );
	}

	/**
	 * Store API cart item schema callback.
	 *
	 * @since 1.0.0
	 * @return array<string, mixed>
	 */
	public function store_api_cart_item_schema(): array {
		return array(
			'estimate' => array(
				'description' => __( 'Estimated delivery for this cart item.', 'wpactpro-estimated-delivery-date' ),
				'type'        => array( 'object', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
		);
	}

	/**
	 * Schema for the product `estimated_delivery` field.
	 *
	 * @since 1.0.0
	 * @return array<string, mixed>
	 */
	private function product_schema(): array {
		return array(
			'description' => __( 'Estimated delivery window for this product.', 'wpactpro-estimated-delivery-date' ),
			'type'        => array( 'object', 'null' ),
			'context'     => array( 'view', 'edit' ),
			'readonly'    => true,
			'properties'  => array(
				'enabled'        => array( 'type' => 'boolean' ),
				'min_days'       => array( 'type' => array( 'integer', 'null' ) ),
				'max_days'       => array( 'type' => array( 'integer', 'null' ) ),
				'from'           => array(
					'type'        => array( 'string', 'null' ),
					'description' => __( 'Earliest delivery date (Y-m-d).', 'wpactpro-estimated-delivery-date' ),
				),
				'to'             => array(
					'type'        => array( 'string', 'null' ),
					'description' => __( 'Latest delivery date (Y-m-d).', 'wpactpro-estimated-delivery-date' ),
				),
				'from_formatted' => array( 'type' => array( 'string', 'null' ) ),
				'to_formatted'   => array( 'type' => array( 'string', 'null' ) ),
				'text'           => array(
					'type'        => 'string',
					'description' => __( 'Formatted delivery date range.', 'wpactpro-estimated-delivery-date' ),
				),
			),
		);
	}
}
