<?php
/**
 * Order Sync Class for Inventory Management
 *
 * @package FunnelKit_Square
 */

namespace FKWCSQ\Includes\Sync;

use FKWCSQ\Includes\Logger;
use FKWCSQ\Includes\Traits\Instance;
use Exception;
use WC_Order;
use WC_Product;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

/**
 * Handles inventory synchronization between WooCommerce and Square during order events
 */
class Order {
	use Instance;

	/**
	 * Square API instance
	 *
	 * @var \FKWCSQ\Includes\API
	 */
	private $api;

	/**
	 * Array of products to sync
	 *
	 * @var array
	 */
	private $products_to_sync = array();

	/**
	 * Constructor
	 */
	private function __construct() {

		// Initialize API
		try {
			$this->api = \FKWCSQ\Includes\API::get_instance();
		} catch ( Exception $e ) {
			// API initialization failed
		}

		// Stock management hooks
		add_action('woocommerce_reduce_order_item_stock', array( $this, 'stage_stock_update_for_product' ), 10, 3);
		add_action('woocommerce_reduce_order_stock', array( $this, 'sync_staged_inventory_updates' ), 10, 1);

		// Stock restoration hooks for cancelled/refunded orders
		add_action('woocommerce_order_status_cancelled', array( $this, 'sync_inventory_for_stock_increase' ), 10, 1);
		add_action('woocommerce_order_status_refunded', array( $this, 'sync_inventory_for_stock_increase' ), 10, 1);
		add_action('woocommerce_order_status_failed', array( $this, 'sync_inventory_for_stock_increase' ), 10, 1);
	}

	/**
	 * Stage stock updates for a product when order item stock is reduced
	 *
	 * @param \WC_Order_Item_Product $item
	 * @param array $change
	 * @param \WC_Order $order
	 * @return bool Success status
	 */
	public function stage_stock_update_for_product( $item, $change, $order ) {
		// Get product from the change data
		$product = isset($change['product']) ? $change['product'] : false;

		if ( ! $product ) {
			return false;
		}

		// Only proceed if product manages stock
		if ( ! $product->managing_stock() ) {
			return false;
		}

		// Only proceed if product should sync with Square
		if ( ! \FKWCSQ\Square::should_sync_product_with_square( $product->get_id() ) ) {
			return false;
		}

		// Get stock change values
		$previous = isset($change['from']) ? $change['from'] : false;
		$current = isset($change['to']) ? $change['to'] : false;

		if ( false === $previous || false === $current ) {
			return false;
		}

		$product_id = $product->get_id();

		// Only proceed if product has a Square ID
		$square_id = $this->get_product_square_id($product);
		if ( ! $square_id ) {
			return false;
		}

		// Store current quantity for syncing later
		$this->products_to_sync[ $product_id ] = array(
			'square_id' => $square_id,
			'quantity'  => $current,
		);

		return true;
	}

	/**
	 * Sync staged inventory updates to Square
	 *
	 * @param \WC_Order $order The order being processed
	 * @return array Summary of sync results
	 */
	public function sync_staged_inventory_updates( $order ) {
		$total_products = 0;
		$success_count = 0;
		$failed_count = 0;
		$errors = array();

		if ( empty($this->products_to_sync) ) {
			return array( 'total' => 0, 'success' => 0, 'failed' => 0, 'errors' => array() );
		}

		$total_products = count($this->products_to_sync);

		foreach ( $this->products_to_sync as $product_id => $data ) {
			$square_id = $data['square_id'];
			$quantity = $data['quantity'];

			try {
				// Ensure API method exists
				if ( ! method_exists($this->api, 'update_inventory') ) {
					++$failed_count;
					$errors[] = sprintf('Product #%d: API method update_inventory does not exist', $product_id);
					continue;
				}

				$inventory_data = array(
					'quantity'    => $quantity,
					'location_id' => $this->api->get_location_id(),
				);

				// Send updated inventory to Square
				$result = $this->api->update_inventory($square_id, $inventory_data);

				if ( is_wp_error($result) ) {
					++$failed_count;
					$errors[] = sprintf('Product #%d: %s', $product_id, $result->get_error_message());
				} else {
					++$success_count;
				}
			} catch ( Exception $e ) {
				++$failed_count;
				$errors[] = sprintf('Product #%d: %s', $product_id, $e->getMessage());
			}
		}

		// Log summary
		$message = sprintf('Order #%d inventory sync: %d total, %d successful, %d failed',
			$order->get_id(), $total_products, $success_count, $failed_count);

		if ( $failed_count > 0 && ! empty( $errors ) ) {
			$message .= ' - Errors: ' . implode( '; ', array_slice( $errors, 0, 3 ) );
			if ( count( $errors ) > 3 ) {
				$message .= ' (and ' . ( count( $errors ) - 3 ) . ' more)';
			}
		}

		Logger::info( $message );

		// Clear staged products
		$this->products_to_sync = array();

		return array( 'total' => $total_products, 'success' => $success_count, 'failed' => $failed_count, 'errors' => $errors );
	}

	/**
	 * Handle inventory increases when orders are cancelled, refunded, or failed
	 *
	 * @param int $order_id
	 * @return array Summary of sync results
	 */
	public function sync_inventory_for_stock_increase( $order_id ) {
		$total_products = 0;
		$success_count = 0;
		$failed_count = 0;
		$errors = array();

		$order = wc_get_order($order_id);
		if ( ! $order ) {
			return array( 'total' => 0, 'success' => 0, 'failed' => 0, 'errors' => array() );
		}

		// Check if stock was reduced for this order
		$stock_reduced = $order->get_meta('_order_stock_reduced');
		if ( ! $stock_reduced ) {
			return array( 'total' => 0, 'success' => 0, 'failed' => 0, 'errors' => array() );
		}

		// Clear existing staged updates
		$this->products_to_sync = array();

		// Process each item
		foreach ( $order->get_items() as $item ) {
			$product = $item->get_product();
			if ( ! $product || ! $product->managing_stock() ) {
				continue;
			}

			// Only proceed if product should sync with Square
			if ( ! \FKWCSQ\Square::should_sync_product_with_square( $product->get_id() ) ) {
				continue;
			}

			$product_id = $product->get_id();
			$square_id = $this->get_product_square_id($product);

			if ( ! $square_id ) {
				continue;
			}

			// Get current stock level
			$current_stock = $product->get_stock_quantity();

			// Store for syncing
			$this->products_to_sync[ $product_id ] = array(
				'square_id' => $square_id,
				'quantity'  => $current_stock,
			);
		}

		$total_products = count($this->products_to_sync);

		// If we have products to sync, do it now
		if ( ! empty($this->products_to_sync) ) {
			$result = $this->sync_staged_inventory_updates($order);

			// Log summary for stock increase
			$message = sprintf('Order #%d stock restoration: %d total, %d successful, %d failed',
				$order_id, $result['total'], $result['success'], $result['failed']);

			if ( $result['failed'] > 0 && ! empty( $result['errors'] ) ) {
				$message .= ' - Errors: ' . implode( '; ', array_slice( $result['errors'], 0, 3 ) );
				if ( count( $result['errors'] ) > 3 ) {
					$message .= ' (and ' . ( count( $result['errors'] ) - 3 ) . ' more)';
				}
			}

			Logger::info( $message );

			return $result;
		}

		return array( 'total' => $total_products, 'success' => 0, 'failed' => 0, 'errors' => array() );
	}


	/**
	 * Check if product should sync with Square
	 *
	 * @param int $product_id Product ID
	 * @return bool
	 */
	private function should_sync_product_with_square( $product_id ) {
		return \FKWCSQ\Square::should_sync_product_with_square( $product_id );
	}

	/**
	 * Get Square ID for a product
	 *
	 * @param \WC_Product $product
	 * @return string|null
	 */
	private function get_product_square_id( $product ) {
		if ( $product->is_type('variation') ) {
			$square_id = $product->get_meta('_square_variation_id');
			return $square_id;
		}

		$square_id = $product->get_meta('_square_id');
		return $square_id;
	}
}
