<?php
/**
 * A1-WooBay - Bidirectional Sync (Phase 3c)
 *
 * Handles two sync directions:
 *   1. WooCommerce → eBay: when stock hits 0, auto-withdraw the eBay offer.
 *   2. eBay → WooCommerce: scheduled cron pulls current qty + price from eBay
 *      and updates WooCommerce products.
 *
 * Available on both plans as of 2026-08-12. Scheduling and the manual
 * "Sync Now" trigger share the same run_pull_sync() body, so there was no
 * way to make automatic scheduling a separately-stripped Pro feature
 * without also breaking the free manual button - removed the restriction
 * entirely rather than ship a runtime-only gate (not acceptable per
 * WP.org Guideline 5).
 *
 * @package A1_WooBay
 * @since   0.6.4
 */

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

class A1WooBay_Sync {

	const CRON_HOOK       = 'a1woobay_pull_sync';
	const OPT_LAST        = 'a1woobay_last_sync';
	const OPT_FREQ        = 'a1woobay_sync_frequency';
	const OPT_PULL_PRICE  = 'a1woobay_sync_pull_price';

	private static ?A1WooBay_Sync $instance = null;

	public static function get_instance(): A1WooBay_Sync {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
		$this->register_hooks();
	}

	// -------------------------------------------------------------------------
	// Hook registration
	// -------------------------------------------------------------------------

	public function register_hooks(): void {
		// Cron pull sync
		add_action( self::CRON_HOOK, array( $this, 'run_pull_sync' ) );

		// Schedule cron on init (respects saved frequency setting). Available
		// on both plans - see class docblock.
		add_action( 'init', array( $this, 'schedule_cron' ) );
	}

	// -------------------------------------------------------------------------
	// Cron scheduling helpers
	// -------------------------------------------------------------------------

	public function schedule_cron(): void {
		$freq = get_option( self::OPT_FREQ, 'hourly' );

		if ( 'disabled' === $freq ) {
			$this->clear_cron();
			return;
		}

		$next = wp_next_scheduled( self::CRON_HOOK );

		if ( false === $next ) {
			wp_schedule_event( time(), $freq, self::CRON_HOOK );
		} else {
			// If frequency changed, reschedule
			$schedules = wp_get_schedules();
			if ( isset( $schedules[ $freq ] ) ) {
				$interval = $schedules[ $freq ]['interval'];
				// If the next scheduled time is more than one interval away (or less than 0), reschedule
				$age = time() - ( $next - $interval );
				if ( $age < 0 ) {
					$this->clear_cron();
					wp_schedule_event( time(), $freq, self::CRON_HOOK );
				}
			}
		}
	}

	public function clear_cron(): void {
		$timestamp = wp_next_scheduled( self::CRON_HOOK );
		if ( $timestamp ) {
			wp_unschedule_event( $timestamp, self::CRON_HOOK );
		}
	}

	// -------------------------------------------------------------------------
	// eBay → WC pull sync (cron callback + manual trigger)
	// -------------------------------------------------------------------------

	public function run_pull_sync(): array {
		$api = A1WooBay_API::get_instance();

		// Get all ACTIVE products
		$query = new WP_Query( array(
			'post_type'      => 'product',
			'post_status'    => 'publish',
			'posts_per_page' => -1,
			'meta_query'     => array(
				array(
					'key'   => A1WooBay_Product_Meta::META_EBAY_STATUS,
					'value' => A1WooBay_Product_Meta::STATUS_ACTIVE,
				),
			),
		) );

		$total   = $query->post_count;
		$updated = 0;
		$errors  = 0;
		$log     = array();

		foreach ( $query->posts as $post ) {
			$pid      = $post->ID;
			$product  = wc_get_product( $pid );
			if ( ! $product ) {
				continue;
			}

			$sku      = $product->get_sku();
			$offer_id = A1WooBay_Product_Meta::get_offer_id( $pid );

			if ( ! $sku ) {
				continue;
			}

			$changed = false;

			// --- Qty: pull from inventory item ---
			$inv = $api->get_inventory_item( $sku );
			if ( ! is_wp_error( $inv ) && isset( $inv['availability']['shipToLocationAvailability']['quantity'] ) ) {
				$ebay_qty = (int) $inv['availability']['shipToLocationAvailability']['quantity'];
				$wc_qty   = (int) $product->get_stock_quantity();

				if ( $ebay_qty !== $wc_qty ) {
					$product->set_manage_stock( true );
					$product->set_stock_quantity( $ebay_qty );
					$product->set_stock_status( $ebay_qty > 0 ? 'instock' : 'outofstock' );
					$changed = true;
					$log[]   = "#{$pid} qty {$wc_qty}→{$ebay_qty}";
				}
			} else {
				$errors++;
			}

			// --- Price: pull from offer (only if enabled in settings) ---
			if ( $offer_id && get_option( self::OPT_PULL_PRICE, '0' ) ) {
				$offer = $api->get_offer( $offer_id );
				if ( ! is_wp_error( $offer ) && isset( $offer['pricingSummary']['price']['value'] ) ) {
					$ebay_price = (float) $offer['pricingSummary']['price']['value'];
					$wc_price   = (float) $product->get_regular_price();

					if ( abs( $ebay_price - $wc_price ) > 0.001 ) {
						$product->set_regular_price( (string) $ebay_price );
						$changed = true;
						$log[]   = "#{$pid} price {$wc_price}→{$ebay_price}";
					}
				}
			}

			if ( $changed ) {
				$product->save();
				$updated++;
			}

			// Avoid hammering the API
			usleep( 150000 ); // 150 ms between products
		}

		$result = array(
			'time'    => current_time( 'mysql' ),
			'total'   => $total,
			'updated' => $updated,
			'errors'  => $errors,
			'log'     => array_slice( $log, 0, 50 ), // cap log at 50 entries
		);

		update_option( self::OPT_LAST, $result );
		return $result;
	}
}
