<?php
/**
 * WooCommerce Shipping Fulfillments Data Store class.
 *
 * Extends the core FulfillmentsDataStore to return ShippingFulfillment objects
 * instead of the base Fulfillment objects.
 *
 * @package WCShipping\Fulfillments
 * @since   1.9.0
 */

declare( strict_types=1 );

namespace Automattic\WCShipping\Fulfillments;

defined( 'ABSPATH' ) || exit;

// Only extend the parent class if it exists (requires WooCommerce 10.1+)
if ( class_exists( '\Automattic\WooCommerce\Internal\DataStores\Fulfillments\FulfillmentsDataStore' ) ) {
	/**
	 * Shipping Fulfillments Data Store Class
	 *
	 * Extends the core FulfillmentsDataStore to return ShippingFulfillment objects
	 * which provide additional shipping-specific functionality.
	 *
	 * @since 1.9.0
	 */
	class ShippingFulfillmentsDataStore extends \Automattic\WooCommerce\Internal\DataStores\Fulfillments\FulfillmentsDataStore {

		/**
		 * Read fulfillments from the database.
		 *
		 * Overrides the parent method to return ShippingFulfillment objects
		 * instead of base Fulfillment objects.
		 *
		 * @param string $entity_type The entity type (e.g., 'WC_Order').
		 * @param string $entity_id The entity ID.
		 * @param bool   $with_deleted Whether to include deleted fulfillments.
		 *
		 * @return ShippingFulfillment[] Array of ShippingFulfillment objects.
		 *
		 * @throws \Exception If failed to read fulfillment data.
		 */
		public function read_fulfillments( string $entity_type, string $entity_id, bool $with_deleted = false ): array {
			// Read the fulfillment data from the database.
			global $wpdb;

			if ( ! $with_deleted ) {
				$fulfillment_data = $wpdb->get_results(
					$wpdb->prepare(
						"SELECT * FROM {$wpdb->prefix}wc_order_fulfillments WHERE entity_type = %s AND entity_id = %s AND date_deleted IS NULL",
						$entity_type,
						$entity_id
					),
					ARRAY_A
				);
			} else {
				$fulfillment_data = $wpdb->get_results(
					$wpdb->prepare(
						"SELECT * FROM {$wpdb->prefix}wc_order_fulfillments WHERE entity_type = %s AND entity_id = %s",
						$entity_type,
						$entity_id
					),
					ARRAY_A
				);
			}

			if ( is_wp_error( $fulfillment_data ) ) {
				throw new \Exception( esc_html__( 'Failed to read fulfillment data.', 'woocommerce-shipping' ) );
			}

			// Create ShippingFulfillment objects from the data.
			$fulfillments = array();
			foreach ( $fulfillment_data as $data ) {
				// Note: Don't initialize with ID, it will cause a re-read from the database.
				// Set the ID directly after the object is created.
				$fulfillment = new ShippingFulfillment();
				$fulfillment->set_id( $data['fulfillment_id'] );
				$fulfillment->set_props( $data );
				$fulfillment->apply_changes();
				$fulfillment->set_object_read( true );

				// Read the metadata for the fulfillment.
				$fulfillment->read_meta_data( true );

				$fulfillments[] = $fulfillment;
			}

			return $fulfillments;
		}

		/**
		 * Find a fulfillment by label ID.
		 *
		 * Searches all fulfillments to find one that contains a label with the specified ID.
		 * Returns the first matching fulfillment found.
		 *
		 * @param string $label_id The label ID to search for.
		 *
		 * @return ShippingFulfillment|null ShippingFulfillment object if found, null otherwise.
		 *
		 * @throws \Exception If failed to search fulfillment data.
		 */
		public function get_by_label_id( string $label_id ): ?ShippingFulfillment {
			global $wpdb;

			// First try the fast lookup using individual label_id meta entries
			$fulfillment_data = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT f.* FROM {$wpdb->prefix}wc_order_fulfillments f
				INNER JOIN {$wpdb->prefix}wc_order_fulfillment_meta fm 
				ON f.fulfillment_id = fm.fulfillment_id
				WHERE f.date_deleted IS NULL 
				AND fm.meta_key = %s 
				AND fm.meta_value = %s",
					'_shipping_label_id',
					$label_id
				),
				ARRAY_A
			);

			if ( is_wp_error( $fulfillment_data ) ) {
				throw new \Exception( esc_html__( 'Failed to search fulfillment data.', 'woocommerce-shipping' ) );
			}

			// If no results found, return null
			if ( empty( $fulfillment_data ) ) {
				return null;
			}

			// Create ShippingFulfillment object from the first result
			$data        = $fulfillment_data[0];
			$fulfillment = new ShippingFulfillment();
			$fulfillment->set_id( $data['fulfillment_id'] );
			$fulfillment->set_props( $data );
			$fulfillment->apply_changes();
			$fulfillment->set_object_read( true );

			// Read the metadata for the fulfillment
			$fulfillment->read_meta_data( true );

			return $fulfillment;
		}
	}
} else {
	/**
	 * Fallback Shipping Fulfillments Data Store Class
	 *
	 * Provides basic functionality when the parent FulfillmentsDataStore class
	 * is not available (WooCommerce < 10.1.0).
	 *
	 * @since 1.9.0
	 */
	class ShippingFulfillmentsDataStore {

		/**
		 * Read fulfillments from the database.
		 *
		 * Basic implementation for when parent class is not available.
		 *
		 * @param string $entity_type The entity type (e.g., 'WC_Order').
		 * @param string $entity_id The entity ID.
		 * @param bool   $with_deleted Whether to include deleted fulfillments.
		 *
		 * @return ShippingFulfillment[] Array of ShippingFulfillment objects.
		 *
		 * @throws \Exception If failed to read fulfillment data.
		 */
		public function read_fulfillments( string $entity_type, string $entity_id, bool $with_deleted = false ): array {

			return array();
		}

		/**
		 * Find a fulfillment by label ID.
		 *
		 * Searches all fulfillments to find one that contains a label with the specified ID.
		 * Returns the first matching fulfillment found.
		 *
		 * @param string $label_id The label ID to search for.
		 *
		 * @return ShippingFulfillment|null ShippingFulfillment object if found, null otherwise.
		 *
		 * @throws \Exception If failed to search fulfillment data.
		 */
		public function get_by_label_id( string $label_id ): ?ShippingFulfillment {
			return null;
		}
	}
}
