<?php
/**
 * Square → WooCommerce inventory sync (inventory.count.updated webhooks).
 *
 * @package SHC4WC
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class SHC4WC_Inventory_Sync {
	const SKU_CACHE_PREFIX = 'shc4wc_inv_sku_';
	const SKU_CACHE_TTL    = 3600;
	const EVENT_CACHE_TTL  = DAY_IN_SECONDS;

	/**
	 * Whether Square → WooCommerce inventory sync is enabled.
	 *
	 * @return bool
	 */
	public static function is_enabled() {
		if ( ! class_exists( 'WooCommerce' ) || ! SHC4WC_Plugin::is_connected() ) {
			return false;
		}

		$settings = SHC4WC_Plugin::get_settings();
		$enabled  = ! isset( $settings['square_inventory_sync_from_square'] ) || 'yes' === $settings['square_inventory_sync_from_square'];

		return (bool) apply_filters( 'shc4wc_inventory_sync_from_square_enabled', $enabled, $settings );
	}

	/**
	 * Handle inventory.count.updated webhook payload.
	 *
	 * @param array<string, mixed> $event Full webhook event.
	 * @param SHC4WC_API             $api   API logger/client.
	 */
	public static function handle_webhook_event( array $event, SHC4WC_API $api ) {
		if ( ! self::is_enabled() ) {
			return;
		}

		$event_id = isset( $event['event_id'] ) ? sanitize_text_field( (string) $event['event_id'] ) : '';
		if ( '' !== $event_id && get_transient( 'shc4wc_inv_evt_' . md5( $event_id ) ) ) {
			return;
		}

		$counts = array();
		if ( ! empty( $event['data']['object']['inventory_counts'] ) && is_array( $event['data']['object']['inventory_counts'] ) ) {
			$counts = $event['data']['object']['inventory_counts'];
		}
		if ( empty( $counts ) ) {
			return;
		}

		$settings    = SHC4WC_Plugin::get_settings();
		$location_id = isset( $settings['location_id'] ) ? trim( (string) $settings['location_id'] ) : '';
		$processed   = 0;

		foreach ( self::normalize_inventory_counts( $counts ) as $count ) {
			if ( self::sync_inventory_count_to_woocommerce( $count, $api, $location_id ) ) {
				++$processed;
			}
		}

		if ( '' !== $event_id ) {
			set_transient( 'shc4wc_inv_evt_' . md5( $event_id ), 1, self::EVENT_CACHE_TTL );
		}

		if ( $processed > 0 ) {
			$api->log(
				'Square inventory webhook synced WooCommerce stock',
				array(
					'event_id'  => $event_id,
					'processed' => $processed,
				)
			);
		}
	}

	/**
	 * Collapse webhook inventory rows to one quantity per catalog object + location.
	 *
	 * @param array<int, array<string, mixed>> $counts Raw webhook counts.
	 * @return array<int, array<string, mixed>>
	 */
	private static function normalize_inventory_counts( array $counts ) {
		$map = array();

		foreach ( $counts as $count ) {
			if ( ! is_array( $count ) ) {
				continue;
			}

			$catalog_object_id = isset( $count['catalog_object_id'] ) ? sanitize_text_field( (string) $count['catalog_object_id'] ) : '';
			$location_id       = isset( $count['location_id'] ) ? sanitize_text_field( (string) $count['location_id'] ) : '';
			if ( '' === $catalog_object_id || '' === $location_id ) {
				continue;
			}

			$key = $catalog_object_id . '|' . $location_id;
			if ( ! isset( $map[ $key ] ) ) {
				$map[ $key ] = $count;
				continue;
			}

			$existing_state = isset( $map[ $key ]['state'] ) ? strtoupper( (string) $map[ $key ]['state'] ) : '';
			$new_state      = isset( $count['state'] ) ? strtoupper( (string) $count['state'] ) : '';
			if ( 'IN_STOCK' === $new_state || 'IN_STOCK' !== $existing_state ) {
				$map[ $key ] = $count;
			}
		}

		return array_values( $map );
	}

	/**
	 * @param array<string, mixed> $count       Single inventory count row.
	 * @param SHC4WC_API           $api         API client.
	 * @param string               $location_id Plugin Square location id.
	 * @return bool True when WooCommerce stock was updated.
	 */
	private static function sync_inventory_count_to_woocommerce( array $count, SHC4WC_API $api, $location_id ) {
		$catalog_object_id = isset( $count['catalog_object_id'] ) ? sanitize_text_field( (string) $count['catalog_object_id'] ) : '';
		$count_location_id = isset( $count['location_id'] ) ? sanitize_text_field( (string) $count['location_id'] ) : '';
		$quantity_raw      = isset( $count['quantity'] ) ? (string) $count['quantity'] : '';

		if ( '' === $catalog_object_id || '' === $count_location_id || '' === $quantity_raw || ! is_numeric( $quantity_raw ) ) {
			return false;
		}

		if ( '' !== $location_id && $location_id !== $count_location_id ) {
			return false;
		}

		$quantity = wc_stock_amount( $quantity_raw );

		$sku = self::get_sku_for_catalog_object( $catalog_object_id, $api );
		if ( '' === $sku ) {
			return false;
		}

		$product_id = wc_get_product_id_by_sku( $sku );
		$product_id = (int) apply_filters( 'shc4wc_inventory_sync_wc_product_id', $product_id, $sku, $catalog_object_id, $count );
		if ( $product_id <= 0 ) {
			$api->log(
				'Square inventory webhook: no WooCommerce product for SKU',
				array(
					'sku'                 => $sku,
					'catalog_object_id'   => $catalog_object_id,
					'location_id'         => $count_location_id,
				),
				'info'
			);
			return false;
		}

		$product = wc_get_product( $product_id );
		if ( ! $product ) {
			return false;
		}

		$quantity = (float) apply_filters( 'shc4wc_inventory_sync_quantity', (float) $quantity, $product, $sku, $catalog_object_id, $count );
		$current  = $product->managing_stock() ? (float) $product->get_stock_quantity() : null;
		if ( null !== $current && abs( $current - $quantity ) < 0.00001 ) {
			return false;
		}

		$product->set_manage_stock( true );
		$product->set_stock_quantity( $quantity );
		$product->save();

		$api->log(
			'WooCommerce stock updated from Square inventory webhook',
			array(
				'product_id'          => $product_id,
				'sku'                 => $sku,
				'catalog_object_id'   => $catalog_object_id,
				'location_id'         => $count_location_id,
				'quantity'            => $quantity,
			)
		);

		return true;
	}

	/**
	 * @param string     $catalog_object_id Square catalog object id.
	 * @param SHC4WC_API $api               API client.
	 * @return string SKU or empty.
	 */
	private static function get_sku_for_catalog_object( $catalog_object_id, SHC4WC_API $api ) {
		$catalog_object_id = sanitize_text_field( (string) $catalog_object_id );
		if ( '' === $catalog_object_id ) {
			return '';
		}

		$cache_key = self::SKU_CACHE_PREFIX . md5( $catalog_object_id );
		$cached    = get_transient( $cache_key );
		if ( is_string( $cached ) ) {
			return $cached;
		}

		$response = $api->retrieve_catalog_object( $catalog_object_id );
		$sku      = '';
		if ( ! is_wp_error( $response ) && ! empty( $response['object'] ) && is_array( $response['object'] ) ) {
			$sku = self::extract_sku_from_catalog_object( $response['object'] );
		}

		set_transient( $cache_key, $sku, self::SKU_CACHE_TTL );

		return $sku;
	}

	/**
	 * @param array<string, mixed> $object Catalog object from Square.
	 * @return string
	 */
	private static function extract_sku_from_catalog_object( array $object ) {
		if ( ! empty( $object['item_variation_data']['sku'] ) ) {
			return sanitize_text_field( (string) $object['item_variation_data']['sku'] );
		}
		if ( ! empty( $object['item_data']['variations'] ) && is_array( $object['item_data']['variations'] ) ) {
			foreach ( $object['item_data']['variations'] as $variation ) {
				if ( is_array( $variation ) && ! empty( $variation['item_variation_data']['sku'] ) ) {
					return sanitize_text_field( (string) $variation['item_variation_data']['sku'] );
				}
			}
		}

		return '';
	}
}
