<?php
/**
 * Store details synchronisation with MEM.
 *
 * Detects changes to tracked WordPress/WooCommerce settings and
 * version numbers, then sends only the changed fields to the MEM
 * backend via the update-store-details API.
 *
 * Tracked fields:
 *   siteName, timezone, currency, countryCode,
 *   pluginVersion, woocommerceVersion, phpVersion
 *
 * @package Memwc_Connector
 * @since   1.0.0
 */

defined( 'ABSPATH' ) || exit;

class Memwc_Store_Sync {

	private static $instance = null;

	/**
	 * Option key where the last-known snapshot is stored.
	 */
	const SNAPSHOT_KEY = 'memwc_connector_store_snapshot';

	/**
	 * Maps snapshot keys to the WordPress options that drive them.
	 * Version fields are not option-driven and are checked separately.
	 */
	private static $option_field_map = array(
		'blogname'                     => 'siteName',
		'timezone_string'              => 'timezone',
		'gmt_offset'                   => 'timezone',
		'woocommerce_currency'         => 'currency',
		'woocommerce_default_country'  => 'countryCode',
	);

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

	private function __construct() {
		// React to individual option changes (fires the moment the setting is saved).
		foreach ( array_keys( self::$option_field_map ) as $option_name ) {
			add_action( "update_option_{$option_name}", array( $this, 'on_option_changed' ), 10, 3 );
		}

		// Detect version changes on admin_init (plugin update, WC update, PHP upgrade).
		add_action( 'admin_init', array( $this, 'check_version_changes' ) );
	}

	// =========================================================================
	// Option change handler
	// =========================================================================

	/**
	 * Fired when a tracked WP/WC option is updated.
	 *
	 * @param mixed  $old_value   Previous value.
	 * @param mixed  $new_value   New value.
	 * @param string $option_name The option name.
	 */
	public function on_option_changed( $old_value, $new_value, $option_name ) {
		if ( ! Memwc_Connector::is_connected() ) {
			return;
		}

		$field_name = self::$option_field_map[ $option_name ] ?? null;
		if ( ! $field_name ) {
			return;
		}

		$value    = $this->resolve_field_value( $field_name, $new_value );
		$snapshot = get_option( self::SNAPSHOT_KEY, array() );

		// Compare against the snapshot to avoid duplicate sends
		// (e.g. timezone_string and gmt_offset both map to 'timezone').
		if ( ( $snapshot[ $field_name ] ?? '' ) === $value ) {
			return;
		}

		$snapshot[ $field_name ] = $value;
		update_option( self::SNAPSHOT_KEY, $snapshot, false );

		Memwc_Api::update_store_details( array( $field_name => $value ) );
	}

	// =========================================================================
	// Version change detection
	// =========================================================================

	/**
	 * Compare current versions against the stored snapshot.
	 * Sends any changed version fields to MEM.
	 */
	public function check_version_changes() {
		if ( ! Memwc_Connector::is_connected() ) {
			return;
		}

		$snapshot = get_option( self::SNAPSHOT_KEY, array() );
		$changed  = array();

		$version_fields = array(
			'pluginVersion'      => MEMWC_CONNECTOR_VERSION,
			'woocommerceVersion' => defined( 'WC_VERSION' ) ? WC_VERSION : '',
			'phpVersion'         => phpversion(),
		);

		foreach ( $version_fields as $field => $current ) {
			if ( ( $snapshot[ $field ] ?? '' ) !== $current ) {
				$changed[ $field ]  = $current;
				$snapshot[ $field ] = $current;
			}
		}

		if ( ! empty( $changed ) ) {
			update_option( self::SNAPSHOT_KEY, $snapshot, false );
			Memwc_Api::update_store_details( $changed );
		}
	}

	// =========================================================================
	// Full sync (called after successful connection verification)
	// =========================================================================

	/**
	 * Send a full snapshot of all tracked fields to MEM.
	 *
	 * Should be called once after the store is first connected so the
	 * backend has a complete baseline.
	 */
	public static function send_full_snapshot() {
		$fields = self::gather_current_values();

		update_option( self::SNAPSHOT_KEY, $fields, false );

		Memwc_Api::update_store_details( $fields );
	}

	// =========================================================================
	// Helpers
	// =========================================================================

	/**
	 * Gather current values for all tracked fields.
	 *
	 * @return array Associative array of camelCase field => value.
	 */
	public static function gather_current_values() {
		$country_raw = get_option( 'woocommerce_default_country', '' );
		$country     = strpos( $country_raw, ':' ) !== false
			? strstr( $country_raw, ':', true )
			: $country_raw;

		return array(
			'siteName'           => get_option( 'blogname', '' ),
			'timezone'           => wp_timezone_string(),
			'currency'           => function_exists( 'get_woocommerce_currency' ) ? get_woocommerce_currency() : '',
			'countryCode'        => $country,
			'pluginVersion'      => MEMWC_CONNECTOR_VERSION,
			'woocommerceVersion' => defined( 'WC_VERSION' ) ? WC_VERSION : '',
			'phpVersion'         => phpversion(),
		);
	}

	/**
	 * Resolve the value to send for a given field, using the raw
	 * new option value when available.
	 *
	 * @param string $field_name camelCase field name.
	 * @param mixed  $raw_value  The new option value from WordPress.
	 * @return string
	 */
	private function resolve_field_value( $field_name, $raw_value ) {
		if ( 'timezone' === $field_name ) {
			// wp_timezone_string() resolves both named timezones and UTC offsets.
			return wp_timezone_string();
		}

		if ( 'countryCode' === $field_name ) {
			return strpos( $raw_value, ':' ) !== false
				? strstr( $raw_value, ':', true )
				: $raw_value;
		}

		return (string) $raw_value;
	}
}
