<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName

namespace Uncanny_Automator;

/**
 * Class Ameliabooking_Helpers
 *
 * @package Uncanny_Automator
 */
class Ameliabooking_Helpers {


	/**
	 * The options.
	 *
	 * @var mixed The options.
	 */
	public $options;

	/**
	 * The settings tab.
	 *
	 * @var string The settings tab.
	 */
	public $setting_tab;

	/**
	 * The trigger options.
	 *
	 * @var mixed The trigger options.
	 */
	public $load_options = true;


	/**
	 *
	 */
	public function __construct() {

		global $wpdb;

		$this->load_options = Automator()->helpers->recipe->maybe_load_trigger_options( __CLASS__ );

		add_action( 'wp_ajax_ameliabooking_service_category_endpoint', array( $this, 'ameliabooking_service_category_endpoint' ) );

		add_action( 'AmeliaBookingAddedBeforeNotify', array( $this, 'normalize_booking_data' ), 10, 2 );
		add_action( 'amelia_after_appointment_added', array( $this, 'normalize_appointment_data' ), 10, 3 );
	}

	/**
	 * Set the options.
	 *
	 * @param Ameliabooking_Helpers $options
	 */
	public function setOptions( Ameliabooking_Helpers $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
		$this->options = $options;
	}

	/**
	 * @param $trigger_code
	 * @param $trigger_meta
	 *
	 * @return array[]
	 */
	public function get_option_fields( $trigger_code = '', $trigger_meta = '' ) {
		return array(
			$trigger_meta => array(
				array(
					'input_type'      => 'select',
					'option_code'     => $trigger_code . '_SERVICES',
					'required'        => true,
					'label'           => esc_html_x( 'Category', 'Ameliabooking', 'uncanny-automator' ),
					'options'         => $this->get_services_categories(),
					'is_ajax'         => true,
					'endpoint'        => 'ameliabooking_service_category_endpoint',
					'fill_values_in'  => $trigger_meta,
					'relevant_tokens' => array(),
				),
				array(
					'input_type'      => 'select',
					'option_code'     => $trigger_meta,
					'required'        => true,
					'label'           => esc_html_x( 'Service', 'Ameliabooking', 'uncanny-automator' ),
					'relevant_tokens' => array(),
				),
			),
		);
	}

	/**
	 * Callback method to wp_ajax_ameliabooking_service_category_endpoint.
	 *
	 * @return void
	 */
	public function ameliabooking_service_category_endpoint() {

		Automator()->utilities->ajax_auth_check();

		$category_id = absint( automator_filter_input( 'value', INPUT_POST ) );

		$items = array(
			array(
				'text'  => esc_html_x( 'Any service', 'Ameliabooking', 'uncanny-automator' ),
				'value' => '-1',
			),
		);

		$services = $this->get_services_by_category( $category_id );

		if ( ! empty( $services ) ) {
			foreach ( $services as $service ) {
				$items[] = array(
					'text'  => $service->name,
					'value' => $service->id,
				);
			}
		}

		wp_send_json( $items );
	}

	/**
	 * Get amelia services categories.
	 *
	 * @return array The amelia services categories.
	 */
	public function get_services_categories() {

		global $wpdb;

		$items = array();

		$categories = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, name FROM {$wpdb->prefix}amelia_categories WHERE status = %s ORDER BY name ASC LIMIT 100",
				'visible'
			),
			OBJECT
		);

		if ( ! empty( $categories ) ) {
			foreach ( $categories as $category ) {
				$items[ $category->id ] = $category->name;
			}
		}

		return $items;
	}

	/**
	 * Get all amelia services by category.
	 *
	 * @return array The wpdb query result.
	 */
	public function get_services_by_category( $category_id = 0 ) {

		global $wpdb;

		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, name FROM {$wpdb->prefix}amelia_services
				WHERE categoryId = %d AND status = %s
				ORDER BY name ASC LIMIT 100",
				$category_id,
				'visible'
			),
			OBJECT
		);
	}

	/**
	 * Get all amelia services.
	 *
	 * @return array The amelia services returned by wpdb get_results.
	 */
	public function get_services_all() {

		global $wpdb;

		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, name FROM {$wpdb->prefix}amelia_services WHERE status = %s ORDER BY name ASC LIMIT 999",
				'visible'
			),
			OBJECT
		);
	}

	/**
	 * @return array
	 */
	public function get_events_dropdown() {

		$events = $this->get_events();

		$options = array(
			'-1' => esc_attr_x( 'Any event', 'Ameliabooking', 'uncanny-automator' ),
		);

		if ( ! empty( $events ) ) {
			foreach ( $events as $event ) {
				if ( ! empty( $event->name ) && ! empty( $event->id ) ) {
					$options[ $event->id ] = $event->name;
				}
			}
		}

		return $options;
	}

	/**
	 * @return array|object|\stdClass[]|null
	 */
	public function get_events() {

		global $wpdb;

		$options = array();

		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, name from {$wpdb->prefix}amelia_events WHERE status = %s ORDER BY name ASC LIMIT 999",
				'approved'
			),
			OBJECT
		);

		return $results;
	}

	/**
	 * Validate trigger.
	 *
	 * @return boolean False if args is empty. Otherwise, True.
	 */
	public function validate_trigger( $args = array() ) {

		// Bailout if args is empty.
		if ( empty( $args ) ) {
			return false;
		}

		$booking = array_shift( $args[0] );

		if ( empty( $booking['type'] ) ) {
			return false;
		}

		// Only run for appointments. Dont run for events.
		if ( 'appointment' === $booking['type'] ) {
			return true;
		}

		return false;
	}

	/**
	 * Method get_event_date.
	 *
	 * @param array $reservation The reservation array from Amelia hook.
	 *
	 * @return string The event date.
	 */
	public function get_event_date( $reservation = array() ) {

		$reservation_periods = isset( $reservation['event']['periods'][0] ) ? $reservation['event']['periods'][0] : '';

		$period_end = isset( $reservation_periods['periodEnd'] ) ? $reservation_periods['periodEnd'] : '';

		$period_start = isset( $reservation_periods['periodStart'] ) ? $reservation_periods['periodStart'] : '';

		return $period_start . ' - ' . $period_end;
	}

	/**
	 * Method get_event_organizer.
	 *
	 * @param  int $organizer_id The organizer|staff|employee id.
	 *
	 * @return string The organizer.
	 */
	public function get_event_organizer( $organizer_id = 0 ) {

		$organizer = $this->get_organizer( $organizer_id );

		if ( ! empty( $organizer ) ) {

			return implode(
				' ',
				array(
					$organizer->firstName, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
					$organizer->lastName, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
				)
			);

		}
	}

	/**
	 * Method get_event_tags.
	 *
	 * @param  array $reservation The reservation array from Amelia Hook.
	 *
	 * @return string The tag [name] from tags array.
	 */
	public function get_event_tags( $reservation = array() ) {

		$tag_string = '';

		if ( isset( $reservation['event']['tags'] ) ) {

			$tags = array_shift( $reservation['event']['tags'] );

			$tag_string = isset( $tags['name'] ) ? $tags['name'] : '';

		}

		return $tag_string;
	}

	/**
	 * Method get_event_staff.
	 *
	 * @param  array $reservation The reservation array from Amelia Hook.
	 *
	 * @return string The provider name.
	 */
	public function get_event_staff( $reservation = array() ) {

		$providers = array();

		if ( ! empty( $reservation['event']['providers'] ) ) {

			foreach ( $reservation['event']['providers'] as $provider ) {

				$providers[] = implode(
					' ',
					array(
						$provider['firstName'],
						$provider['lastName'],
					)
				);

			}

			return implode( ', ', $providers );
		}

		return '';
	}

	/**
	 * Method get_organizer.
	 *
	 * @param  mixed $organizer_id
	 *
	 * @return object WPDB get row result.
	 */
	public function get_organizer( $organizer_id = 0 ) {

		global $wpdb;

		$results = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}amelia_users WHERE id = %d",
				$organizer_id
			)
		);

		return $results;
	}

	/**
	 * Fetches a single coupon from `amelia_coupons` table.
	 *
	 * Amelia does not provide reliable way to retrieve the coupon properties in the Trigger.
	 *
	 * @param int $coupon_id The ID of the coupon.
	 *
	 * @return array The coupon.
	 */
	public function get_coupon( $coupon_id ) {

		global $wpdb;

		return $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}amelia_coupons WHERE id = %d",
				$coupon_id
			),
			ARRAY_A
		);
	}

	/**
	 * Fetches the coupon events with coupon ID.
	 *
	 * @param int $coupon_id The coupon ID.
	 *
	 * @return string The events associated with the coupon. Separated by comma.
	 */
	public function get_coupon_events( $coupon_id ) {

		global $wpdb;

		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT name FROM {$wpdb->prefix}amelia_coupons_to_events as coupons
					INNER JOIN {$wpdb->prefix}amelia_events as events
					ON coupons.eventId = events.id
					WHERE couponId = %d",
				$coupon_id
			),
			ARRAY_A
		);

		return implode( ', ', array_column( $results, 'name' ) );
	}

	/**
	 * Fetches the coupon services with service ID.
	 *
	 * @param int $coupon_id The coupon ID.
	 *
	 * @return string The services associated with the coupon. Separated by comma.
	 */
	public function get_coupon_services( $coupon_id ) {

		global $wpdb;

		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT name FROM {$wpdb->prefix}amelia_coupons_to_events as coupons
					INNER JOIN {$wpdb->prefix}amelia_services as services
					ON coupons.eventId = services.id
					WHERE couponId = %d",
				$coupon_id
			),
			ARRAY_A
		);

		return implode( ', ', array_column( $results, 'name' ) );
	}

	/**
	 * Fetches the total coupon usage.
	 *
	 * @param int $coupon_id The coupon ID.
	 *
	 * @return int The number of coupons left.
	 */
	public function get_coupon_usage_count( $coupon_id ) {

		global $wpdb;

		$results = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT count(*) as total FROM {$wpdb->prefix}amelia_customer_bookings
					WHERE couponId = %d",
				$coupon_id
			),
			ARRAY_A
		);

		return isset( $results['total'] ) ? absint( $results['total'] ) : 0;
	}

	/**
	 * Normalize data from AmeliaBookingAddedBeforeNotify hook.
	 *
	 * @param array $data The booking data.
	 * @param mixed $container The Amelia container object.
	 *
	 * @return void
	 */
	public function normalize_booking_data( $data, $container = null ) {

		if ( empty( $data ) ) {
			return;
		}

		$normalized_data = $this->extract_normalized_data( $data );

		if ( ! empty( $normalized_data ) ) {
			do_action( 'automator_amelia_appointment_booked', $normalized_data );
		}
	}

	/**
	 * Normalize data from amelia_after_appointment_added hook.
	 *
	 * @param array $appointment The appointment data.
	 * @param array $service The service data.
	 * @param array $payment_data The payment data.
	 *
	 * @return void
	 */
	public function normalize_appointment_data( $appointment, $service = null, $payment_data = null ) {

		if ( empty( $appointment ) ) {
			return;
		}

		// The appointment data from amelia_after_appointment_added is already in the right format
		// Just wrap it to match our normalization expectations
		$normalized_data = $this->extract_normalized_data( array( 'appointment' => $appointment ) );

		if ( ! empty( $normalized_data ) ) {
			do_action( 'automator_amelia_appointment_booked', $normalized_data );
		}
	}

	/**
	 * Extract normalized data from either hook format.
	 *
	 * @param array $data The raw data from Amelia hooks.
	 *
	 * @return array Normalized appointment data.
	 */
	private function extract_normalized_data( $data ) {

		$appointment = array();
		$booking     = array();
		$customer    = array();

		if ( isset( $data['appointment'] ) && is_array( $data['appointment'] ) ) {
			$appointment = $data['appointment'];
		}

		if ( isset( $data['booking'] ) && is_array( $data['booking'] ) ) {
			$booking = $data['booking'];
		} elseif ( isset( $appointment['bookings'][0] ) && is_array( $appointment['bookings'][0] ) ) {
			$booking = $appointment['bookings'][0];
		}

		if ( isset( $data['customer'] ) && is_array( $data['customer'] ) ) {
			$customer = $data['customer'];
		} elseif ( isset( $booking['customer'] ) && is_array( $booking['customer'] ) ) {
			$customer = $booking['customer'];
		}

		if ( empty( $appointment ) || empty( $booking ) ) {
			return array();
		}

		return array(
			'appointment' => $appointment,
			'booking'     => $booking,
			'customer'    => $customer,
			'type'        => isset( $data['type'] ) ? $data['type'] : 'appointment',
		);
	}
}
