<?php

class Facet_Wp_Remote_Data_Cache {

	public const PREFIX_PROPERTY_REMOTE_SITE_DATA = 'facetwp_property_remote_site_data_';
	public const PREFIX_SEARCH_REMOTE_SITE_DATA = 'facetwp_search_remote_site_data_';
	public const PROPERTY_FACETWP_WITH_CHOICES = 'facetwp_property_remote_site_facetwp_with_choices_data';
	public const FACETWP_MAP_FACET_SETTINGS = 'facet_wp_map_facet_settings';
	public const PROPERTY_POSTS_REMOTE_SITE_DATA = 'property_posts_remote_site_data_';
	public const FACETWP_LATEST_LISTINGS_REMOTE_SITE_DATA = 'facetwp_latest_listings_remote_site_data_';
	public const FACETWP_CURRENT_LISTINGS_REMOTE_SITE_DATA = 'facetwp_current_listings_remote_site_data_';
	public const FACETWP_MAP_ALL_LOCATIONS = 'facet_wp_map_all_locations';

	public static function get_cache_prefixes() {
		return [
			self::PREFIX_PROPERTY_REMOTE_SITE_DATA,
			self::PREFIX_SEARCH_REMOTE_SITE_DATA,
			self::PROPERTY_FACETWP_WITH_CHOICES,
			self::FACETWP_MAP_FACET_SETTINGS,
			self::PROPERTY_POSTS_REMOTE_SITE_DATA,
			self::FACETWP_LATEST_LISTINGS_REMOTE_SITE_DATA,
			self::FACETWP_CURRENT_LISTINGS_REMOTE_SITE_DATA,
			self::FACETWP_MAP_ALL_LOCATIONS,
			...array_values( Mls::cacheKeys() )
		];
	}

	public static function property_remote_site_data( $property_id ) {
		return self::PREFIX_PROPERTY_REMOTE_SITE_DATA . $property_id;
	}

	public static function remote_site_facet_search_data( $query_args ) {
		if ( is_array( $query_args ) ) {
			$query_args = self::deep_urldecode( $query_args );
		}

		self::recursive_ksort( $query_args );

		return self::PREFIX_SEARCH_REMOTE_SITE_DATA . md5( wp_json_encode( $query_args ) );
	}

	public static function property_posts_remote_site_data( $post_ids ) {
		return self::PROPERTY_POSTS_REMOTE_SITE_DATA . md5( serialize( $post_ids ) );
	}

	public static function remote_site_listings_data( $key, $posts_per_page, $paged ) {
		return $key . $posts_per_page . '_' . $paged;
	}

	public static function remote_site_data_latest_listings( $posts_per_page, $paged ) {
		return self::remote_site_listings_data( self::FACETWP_LATEST_LISTINGS_REMOTE_SITE_DATA, $posts_per_page, $paged );
	}

	public static function remote_site_data_current_listings( $posts_per_page, $paged ) {
		return self::remote_site_listings_data( self::FACETWP_CURRENT_LISTINGS_REMOTE_SITE_DATA, $posts_per_page, $paged );
	}

	public static function all_locations_for_mls( $mls ) {
		return Mls::getCacheKey( $mls );
	}

	public static function set( $transient_key, $data, $expiration = 12 * HOUR_IN_SECONDS ) {
		return wp_using_ext_object_cache()
			? wp_cache_set( $transient_key, $data, 'transient', $expiration )
			: set_transient( $transient_key, $data, $expiration );
	}

	public static function get( $key ) {
		return wp_using_ext_object_cache()
			? wp_cache_get( $key, 'transient' )
			: get_transient( $key );
	}

	public static function delete( $key ) {
		return wp_using_ext_object_cache()
			? wp_cache_delete( $key, 'transient' )
			: delete_transient( $key );
	}


	public function register_cli_command() {
		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			WP_CLI::add_command( 'sw-remote-data-cache-warmup', [ $this, 'warmup_cache' ] );
		}
	}

	public function facetwp_cache_warmup_event() {
		if ( ! wp_next_scheduled( 'facetwp_remote_data_cache_warmup_event' ) ) {
			wp_schedule_event( time(), 'every_6_hours', 'facetwp_remote_data_cache_warmup_event' );
		}
	}

	public function cron_schedules( $schedules ) {
		$schedules['every_6_hours'] = [
			'interval' => 6 * HOUR_IN_SECONDS,
			'display'  => 'Every 6 Hours',
		];

		return $schedules;
	}

	public function warmup_cache() {
		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			WP_CLI::log( 'Starting cache warmup...' );
		}

		Facet_Wp_Remote_Data_Handler::force_cache_update();

		Facet_Wp_Remote_Data_User::force_update_favorites_cache();

		Facet_Wp_Remote_Data_Acf_Helper::force_update_properties_in_acf_fields_cache();

		Facet_Wp_Remote_Data_Neighborhood_Page::force_update_neighborhood_pages_cache();

		if ( defined( 'WP_CLI' ) && WP_CLI ) {
			WP_CLI::success( 'Cache warmup completed!' );
		}
	}

	public static function delete_property_cached_data( $post_id ) {
		$transient_key = self::property_remote_site_data( $post_id );

		$deleted_transient = self::delete( $transient_key );

		return $deleted_transient
			? true
			: new WP_Error( 'no_rows', 'No cached data.', ['status' => 204] );
	}

	public static function delete_cache() {
		global $wpdb;

		$prefixes = self::get_cache_prefixes();

		$deleted = 0;

		if ( wp_using_ext_object_cache() ) {
			// Delete transients stored in the object cache (if not stored in the DB)
			if ( function_exists( 'wp_cache_flush_group' ) ) {
				$deleted = wp_cache_flush_group( 'transient' );
			}
		} else {
			// Delete transients stored in the DB
			if ( $prefixes ) {
				foreach ( $prefixes as $prefix ) {
					$result = $wpdb->query(
						$wpdb->prepare(
							"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
							$wpdb->esc_like( '_transient_' . $prefix ) . '%'
						)
					);

					$deleted += $result ?: 0;
				}
			}
		}

		return $deleted ? true : new WP_Error( 'no_rows', 'No cached data.', ['status' => 204] );
	}

	public static function deep_urldecode( $data ) {
		if ( is_array( $data ) ) {
			return array_map( [ self::class, 'deep_urldecode' ], $data );
		}

		return is_string( $data ) ? urldecode( $data ) : $data;
	}

	private static function recursive_ksort( &$array ) {
		if ( ! is_array( $array ) ) {
			return;
		}

		ksort( $array );

		foreach ( $array as &$value ) {
			if ( is_array( $value ) ) {
				self::recursive_ksort( $value );
			}
		}
	}

}
