<?php

namespace EFFE_Plugin;

/**
 * The class responsible for querying events based on data from Eventbrite API.
 *
 * @since      1.0.0
 * @package    Event_Feed_For_Eventbrite
 * @subpackage Event_Feed_For_Eventbrite/includes
 * @author     Bohemia Plugins <https://www.bohemiaplugins.com>
 * 			   Fullworks <https://fullworks.net/>
 * 			   Automattic <https://automattic.com>
 */
class Eventbrite_Query {

	/**
	 * The name of this plugin.
	 * 
	 * @since    1.3.3
	 * @access   protected
	 * @var      string    $plugin_name    The name of this plugin.
	 */
	protected $plugin_name;

	/**
	 * Current Event Feed ID.
	 * 
	 * @since    1.0.0
	 * @access   protected
	 * @var      string     $feed_id     The ID of the Event Feed.
	 */
	protected $feed_id;

	/**
	 * API results.
	 * 
	 * @since    1.3.3
	 * @access   protected
	 * @var      mixed     $api_results     The results from the API call.
	 */
	protected $api_results;

	/**
	 * Sets up the Eventbrite query.
	 *
	 * @access   public
	 * @param    string     $query     URL query string.
	 */
	public function __construct( $feed_id ) {
		$this->plugin_name = EFFE_PLUGIN_NAME;
		$this->feed_id = $feed_id;
		$this->api_results = '';
	}

	/**
	 * Request events, process arguments and filter data.
	 *
	 * @since    1.0.0
	 * @access   public
	 * @return   array      Array with events data.
	 */
	public function get_feed_events() {
	
		// Array to set Eventbrite API arguments
		$params = array();

		// Get Eventbrite API token from settings
		$options = get_option( $this->plugin_name );

		if( $options ) {

			$params['token'] = isset( $options[ 'api_key' ] ) ? $options[ 'api_key' ] : '';

			if( $params['token'] !== '' ) {

				// Create object from event feed ID
				$feed_obj = new Event_Feed_For_Eventbrite_Feed( $this->feed_id );
				$feed = $feed_obj->get_event_feed_data();
				
				// Get user's organizations
				$params['organization_id'] = $feed->organization;

				// Filter by status
				$params['status'] = 'live';

				// Time filter endpoint
				$params['time_filter'] = 'current_future';

				if ( effe_freemius()->can_use_premium_code__premium_only() ) {

					// Past events
					if( $feed->time_filter && $feed->time_filter == 'past' ) {
						$params['status'] = 'ended,completed';
						$params['time_filter'] = $feed->time_filter;
						$params['order_by'] = 'start_desc';
					}

					// All events
					if( $feed->time_filter && $feed->time_filter == 'all' ) {
						$params['status'] = 'live,started,ended,completed';
						$params['time_filter'] = $feed->time_filter;
						$params['order_by'] = 'start_desc';
					}

				}

				// Make request and apply API related arguments
				$this->api_results = eventbrite()->get_organizations_events( $params );
				
				if ( effe_freemius()->can_use_premium_code__premium_only() ) {

					// Filter private/public events
					$this->filter_events_visibility__premium_only( $feed );

					// Filter by venue
					$this->filter_venue__premium_only( $feed );

					// Filter by title
					$this->filter_name__premium_only( $feed );

					// Filter by location
					$this->filter_location__premium_only( $feed );

					// Filter by description
					$this->filter_description__premium_only( $feed );

					// Filter by organizer
					$this->filter_organizer__premium_only( $feed );

				}

				// Return only live events
				if ( ! in_array( $params['time_filter'], array( 'past', 'all' ) ) ) {
					$this->filter_live_events( $params );
				}

				// Check sales status (if tickets are no longer for sale, set sales status to "Sales ended")
				$this->check_sales_status( $this->api_results->events );

				// Apply sorting
				$this->sort_events( $feed );
				
				// Limit number of events displayed
				$this->limit_events( $feed );

				$events_data = $this->api_results;

			} else {

				$events_data = new \WP_Error( 'tokenmissing', '<p class="event-feed-for-eventbrite-error">' . esc_html__( 'Unable to connect to Eventbrite. Please enter Eventbrite API token', 'event-feed-for-eventbrite' ) . ' <a href="' . esc_url( admin_url( 'edit.php?post_type=event_feed&page=' . $this->plugin_name . '-settings' ) ) . '">' . esc_html__( 'in the plugin settings', 'event-feed-for-eventbrite' ) . '</a>.</p>' );
			}

		} else {

			$events_data = new \WP_Error( 'tokenmissing', '<p class="event-feed-for-eventbrite-error">' . esc_html__( 'Unable to connect to Eventbrite. Please enter Eventbrite API token', 'event-feed-for-eventbrite' ) . ' <a href="' . esc_url( admin_url( 'edit.php?post_type=event_feed&page=' . $this->plugin_name . '-settings' ) ) . '">' . esc_html__( 'in the plugin settings', 'event-feed-for-eventbrite' ) . '</a>.</p>' );

		}

		return $events_data;

	}

	/**
	 * Filter out live events that are past their end time.
	 *
	 * @access   protected
	 * @return   array       Array with filtered events data.
	 */
	protected function filter_live_events( $params ) {
		if ( isset( $params['status'] ) && 'live' == $params['status'] )  {
			$this->api_results->events = array_filter(
				$this->api_results->events,
				function ( $event )  {
					$event_end = strtotime( $event->end->utc );
					$result = ( $event_end > time() );
					return $result;
				}
			);
		}
	}

	/**
	 * Check sales status (if tickets are no longer for sale, set sales status to Sold out).
	 *
	 * @since    1.0.0
	 */
	public function check_sales_status( $events ) {
		foreach( $events as $event ) {
			$on_sale = false;
			$now = strtotime( 'now' );
			foreach( $event->tickets as $ticket ) {
				$sales_end = strtotime( $ticket->sales_end );
				if( $sales_end > $now ) {
					$on_sale = true;
				}
			}
			if( $on_sale == false ) {
				$event->event_sales_status->sales_status = 'sales_ended';
			}
		}
	}

	/**
	 * Sort events.
	 *
	 * @access   private
	 * @return   bool       True       if properties match, false otherwise.
	 */
	private function sort_events( $feed ) {
		if( in_array( $feed->time_filter, array( 'past', 'all' ) ) ) {
			usort( $this->api_results->events, array( $this, 'sort_by_date_desc' ) );
		} else {
			usort( $this->api_results->events, array( $this, 'sort_by_date_asc' ) );
		}
	}

	private function sort_by_date_asc( $a, $b ) {
		return strcmp( $a->post_date_gmt, $b->post_date_gmt );
	}

	private function sort_by_date_desc( $a, $b ) {
		return strcmp( $b->post_date_gmt, $a->post_date_gmt );
	}

	/**
	 * Limit number of events displayed.
	 *
	 * @access   protected
	 * @return   array       Array with filtered events data.
	 */
	protected function limit_events( $feed ) {

		// Displayed events settings for different breakpoints
		$events_limit_no = $feed->events_limit_no;
		$events_limit_no_large_tablet = $feed->events_limit_no_large_tablet;
		$events_limit_no_small_tablet = $feed->events_limit_no_small_tablet;
		$events_limit_no_mobile = $feed->events_limit_no_mobile;

		$events_limit = $feed->events_limit;
		$events_limit_large_tablet = $feed->events_limit_large_tablet;
		$events_limit_small_tablet = $feed->events_limit_small_tablet;
		$events_limit_mobile = $feed->events_limit_mobile;

		// Maximum limit from all breakpoints
		$limits = array( $events_limit, $events_limit_large_tablet, $events_limit_small_tablet, $events_limit_mobile );
		$max_limit = max( $limits );

		// If set unlimited on one of the breakpoints, load all events
		if( $events_limit_no == true || $events_limit_no_large_tablet == true || $events_limit_no_small_tablet == true || $events_limit_no_mobile == true ) {
			$max_limit = -1;
		}

		if( $max_limit > 0 ) {
			$this->api_results->events = array_slice( $this->api_results->events, 0, absint( $max_limit ) );
		}
	}

}
