<?php
/**
 * JetEngine compatibility package Query Builder Query class (Appointments).
 */

namespace JET_APB\Compatibility\Packages\Jet_Engine\Query_Builder;

use Jet_Engine\Query_Builder\Queries\Base_Query;
use JET_APB\Plugin;

class Query extends Base_Query {

	/**
	 * Get items.
	 *
	 * Returns queried items array of objects.
	 *
	 * @access public
	 *
	 * @return array
	 */
	public function _get_items() {
		return $this->get_appointment_items();
	}

	/**
	 * Get items total count.
	 *
	 * Returns total found items count.
	 *
	 * @access public
	 *
	 * @return false|int|mixed
	 */
	public function get_items_total_count() {

		$cached = $this->get_cached_data( 'count' );
		if ( false !== $cached ) {
			return $cached;
		}

		$result = count( $this->get_appointment_items( false ) );
		$this->update_query_cache( $result, 'count' );

		return $result;
	}

	/**
	 * Get items pages count.
	 *
	 * Returns queried items pages count.
	 *
	 * @access public
	 *
	 * @return float|int
	 */
	public function get_items_pages_count() {

		$total    = count( $this->get_appointment_items( false ) );
		$per_page = $this->get_items_per_page();

		if ( ! $total || ! $per_page ) {
			return 1;
		}

		return (int) ceil( $total / $per_page );
	}

	/**
	 * Get items page count.
	 *
	 * Returns queried items count per page.
	 *
	 * @access public
	 *
	 * @return false|int|mixed
	 */
	public function get_items_page_count() {

		$result   = $this->get_items_total_count();
		$per_page = $this->get_items_per_page();

		if ( $per_page < $result ) {
			$page  = $this->get_current_items_page();
			$pages = $this->get_items_pages_count();

			if ( $page < $pages ) {
				$result = $per_page;
			} elseif ( absint( $page ) === absint( $pages ) ) {
				$offset = ! empty( $this->final_query['offset'] ) ? absint( $this->final_query['offset'] ) : 0;
				$result = $result - $offset;
			}
		}

		return $result;
	}

	/**
	 * Get current items page.
	 *
	 * Returns currently displayed page number.
	 *
	 * @access public
	 *
	 * @return float|int
	 */
	public function get_current_items_page() {

		$offset   = ! empty( $this->final_query['offset'] ) ? absint( $this->final_query['offset'] ) : 0;
		$per_page = $this->get_items_per_page();

		if ( ! $offset || ! $per_page ) {
			return 1;
		}

		return (int) ceil( $offset / $per_page ) + 1;
	}

	/**
	 * Set filters prop.
	 *
	 * Set filtered prop in specific for current query type way.
	 *
	 * @access public
	 *
	 * @param string $prop  Filter property name.
	 * @param mixed  $value Value to filter property.
	 *
	 * @return void
	 */
	public function set_filtered_prop( $prop = '', $value = null ) {

		switch ( $prop ) {
			case '_page':
				$page = absint( $value );
				if ( 0 < $page ) {
					$this->final_query['offset'] = ( $page - 1 ) * $this->get_items_per_page();
				}
				break;

			case 'orderby':
				if ( is_array( $value ) ) {
					foreach ( $value as $key => $order ) {
						$this->final_query['orderby'][] = [
							'orderby' => $key,
							'order'   => $order,
						];
					}
				}
				break;

			case 'meta_query':
				foreach ( (array) $value as $row ) {
					$this->update_args_row( $row );
				}
				break;

			default:
				$this->update_args_row( [
					'key'     => $prop,
					'value'   => $value,
					'compare' => '=',
				] );
				break;
		}
	}

	/**
	 * Update args row.
	 *
	 * Update args row in specific for current query type way.
	 *
	 * @access public
	 *
	 * @param array $row Query row parameters list.
	 *
	 * @return void
	 */
	public function update_args_row( $row ) {
		if ( ! empty( $row['relation'] ) ) {
			unset( $row['relation'] );

			foreach ( $row as $inner_row ) {
				$this->update_args_row( $inner_row );
			}
		} else {
			$value = ! empty( $row['value'] ) ? $row['value'] : '';

			if ( in_array( $row['key'], array_keys( Plugin::instance()->db->appointments->schema() ) ) ) {
				if ( 'slot' === $row['key'] || 'slot_end' === $row['key'] ) {
					$this->final_query['date_query'][] = [
						'date'    => ! empty( $row['key'] ) ? $row['key'] : false,
						'compare' => ! empty( $row['compare'] ) ? $row['compare'] : '=',
						'value'   => $value,
					];
				} else {
					$this->final_query[ $row['key'] ] = is_array( $value ) ? $value : [ $value ];
				}
			} elseif ( in_array( $row['key'], array_values( Plugin::instance()->settings->get( 'db_columns' ) ) ) ) {
				$this->final_query['meta_query'][] = [
					'column'  => ! empty( $row['key'] ) ? $row['key'] : false,
					'compare' => ! empty( $row['compare'] ) ? $row['compare'] : '=',
					'value'   => $value,
					'type'    => ! empty( $row['type'] ) ? $row['type'] : '',
				];
			}
		}
	}

	/**
	 * Get items per page.
	 *
	 * Returns count of the items visible per single page.
	 *
	 * @access public
	 *
	 * @return int
	 */
	public function get_items_per_page() {

		if ( null === $this->final_query ) {
			$this->setup_query();
		}

		if ( ! empty( $this->final_query['limit'] ) ) {
			return absint( $this->final_query['limit'] );
		}

		return 0;
	}

	/**
	 * Get appointment items.
	 *
	 * Returns list of appointments based on set query parameters.
	 *
	 * @access public
	 *
	 * @param boolean $limit True if limit query output.
	 *
	 * @return array|object|\stdClass[]
	 */
	public function get_appointment_items( $limit = true ) {

		if ( null === $this->final_query ) {
			$this->setup_query();
		}

		$args = $this->final_query;

		if ( ! empty( $args['date_query'] ) ) {
			$date_clause = [
				'relation' => ! empty( $args['date_query_relation'] ) ? $args['date_query_relation'] : 'AND',
			];

			foreach ( $args['date_query'] as $dq ) {
				$date_clause[] = [
					'column'   => $dq['date'] ?? '',
					'operator' => $dq['compare'] ?? '',
					'value'    => $dq['value'] ?? '',
				];
			}

			$args['date_query'] = $date_clause;
		}

		if ( ! empty( $args['meta_query'] ) ) {
			$meta_clause = [
				'relation' => ! empty( $args['meta_query_relation'] ) ? $args['meta_query_relation'] : 'AND',
			];

			foreach ( $args['meta_query'] as $mq ) {
				$meta_clause[] = [
					'column'   => $mq['column'] ?? '',
					'operator' => $mq['compare'] ?? '',
					'value'    => $mq['value'] ?? '',
					'type'     => $mq['type'] ?? '',
				];
			}

			$args['meta_query'] = $meta_clause;
		}

		if ( ! empty( $args['orderby'] ) ) {
			foreach ( $args['orderby'] as $orderby ) {
				$args['sorting'][] = [
					'orderby' => $orderby['orderby'] ?? '',
					'order'   => $orderby['order'] ?? '',
				];
			}
			unset( $args['orderby'] );
		}

		if ( ! $limit ) {
			unset( $args['limit'] );
		}

		$query = new \JET_APB\Resources\Appointment_Query( $args );

		return $query->get_appointments();
	}

	/**
	 * Get args to explode.
	 *
	 * Returns list of arguments where string should be exploded into array.
	 *
	 * @access public
	 *
	 * @return string[]
	 */
	public function get_args_to_explode() {
		return [
			'include',
			'exclude',
			'order_id',
			'user_id',
			'group_ID',
		];
	}
}
