<?php
/**
 * Attendee Page class
 *
 * @link https://www.fooevents.com
 * @package woocommerce-events
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;}


/**
 * Attendee page class
 */
class FooEvents_Attendee_Page {

	/**
	 * Configuration object
	 *
	 * @var array $config
	 */
	public $config;

	/**
	 * FooEvents Cart
	 *
	 * @var array $fooevents_cart
	 */
	public $fooevents_cart;

	/**
	 * FooEvents Form
	 *
	 * @var array $fooevents_form
	 */
	public $fooevents_form;

	/**
	 * Attendee Page ID
	 *
	 * @var array $attendee_page_id
	 */
	public $attendee_page_id;

	/**
	 * Attendee Page URL
	 *
	 * @var array $attendee_page_url
	 */
	public $attendee_page_url;

	/**
	 * FooEvents Custom Attendee Fields
	 *
	 * @var array $fcaf
	 */
	public $fcaf;

	/**
	 * FooEvents Bookings
	 *
	 * @var array $fb
	 */
	public $fb;

	/**
	 * FooEvents Seating
	 *
	 * @var array $fs
	 */
	public $fs;

	/**
	 * On class load
	 *
	 * @param array $config configuration values.
	 */
	public function __construct( $config ) {

		$this->config = $config;

		$this->load_dependencies();
		$this->load_variables();

		require_once $this->config->class_path . '/attendee/class-fooevents-cart.php';
		$this->fooevents_cart = new FooEvents_Cart( $this->config, $this->fcaf, $this->fb, $this->fs );

		require_once $this->config->class_path . '/attendee/class-fooevents-form.php';
		$this->fooevents_form = new FooEvents_Form( $this->config );

		$enable_attendee_page = get_option( 'globalWooCommerceEventsEnableAttendeePage', 'no' );

		if ( 'yes' === $enable_attendee_page ) {

			add_action( 'admin_init', array( $this, 'create_attendee_page' ) );
			add_action( 'wp', array( $this, 'save_attendee_data_to_cart' ) );
			add_action( 'woocommerce_checkout_create_order_line_item', array( $this, 'save_attendee_data_to_order_items' ), 10, 4 );
			add_action( 'template_redirect', array( $this, 'redirect_checkout_if_no_attendees' ) );

			add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'store_attendee_info_from_cart_classic_checkout' ) );

			add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts_frontend' ) );

			add_shortcode( 'fooevents_attendee_form', array( $this, 'display_attendee_form' ) );

		}

		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'store_attendee_info_from_cart' ), 10, 1 );
	}

	/**
	 * Load FooEvents plugin dependencies.
	 */
	public function load_dependencies() {

		$this->fcaf = false;
		$this->fb   = false;
		$this->fs   = false;

		if ( ! is_admin() ) {

			if ( is_plugin_active( 'fooevents_custom_attendee_fields/fooevents-custom-attendee-fields.php' ) || is_plugin_active_for_network( 'fooevents_custom_attendee_fields/fooevents-custom-attendee-fields.php' ) ) {

				$fooevents_custom_attendee_fields = new Fooevents_Custom_Attendee_Fields();
				$this->fcaf                       = $fooevents_custom_attendee_fields->return_attendee_helper();

			}

			if ( is_plugin_active( 'fooevents_bookings/fooevents-bookings.php' ) || is_plugin_active_for_network( 'fooevents_bookings/fooevents-bookings.php' ) ) {

				$fooevents_bookings = new FooEvents_Bookings( true );
				$this->fb           = $fooevents_bookings->return_attendee_helper();

			}

			if ( is_plugin_active( 'fooevents_seating/fooevents-seating.php' ) || is_plugin_active_for_network( 'fooevents_seating/fooevents-seating.php' ) ) {

				$fooevents_seating = new Fooevents_Seating( true );
				$this->fs          = $fooevents_seating->return_attendee_helper();

			}
		}
	}

	/**
	 * Load FooEvents plugin variables.
	 */
	public function load_variables() {

		$default_attende_page = get_page_by_path( 'attendee-details' );

		$attendee_page_id = get_option( 'globalWooCommerceEventsAttendeePage', false );

		if ( empty( $attendee_page_id ) ) {

			$attendee_page_id = $default_attende_page->ID;

		}

		$this->attendee_page_id  = $attendee_page_id;
		$this->attendee_page_url = get_permalink( $attendee_page_id );
	}

	/**
	 * Registers scripts on the WordPress frontend.
	 */
	public function register_scripts_frontend() {

		$vars = array(
			'ajaxurl'       => admin_url( 'admin-ajax.php' ),
			'completeLabel' => __( 'All attendee details captured', 'woocommerce-events' ),
		);

		wp_enqueue_script( 'fooevents-attendee-page', $this->config->scripts_path . '/attendee/fooevents-attendee-page.js', array( 'jquery' ), $this->config->plugin_data['Version'], true );
		wp_localize_script( 'fooevents-attendee-page', 'FooEventsAttendeeVars', $vars );

		wp_enqueue_style( 'dashicons' );
		wp_enqueue_style(
			'fooevents-attendee-page-style',
			$this->config->styles_path . 'attendee/fooevents-attendee-page.css',
			array(),
			$this->config->plugin_data['Version']
		);
	}

	/**
	 * Create capture attendee details page.
	 */
	public function create_attendee_page() {

		$page_title   = __( 'Attendee Details', 'woocommerce-events' );
		$page_content = '[fooevents_attendee_form]';
		$page_slug    = 'attendee-details';

		$page_exists = get_page_by_path( $page_slug, OBJECT, 'page' );

		if ( ! $page_exists ) {

			$page_id = wp_insert_post(
				array(
					'post_title'   => $page_title,
					'post_content' => $page_content,
					'post_status'  => 'publish',
					'post_type'    => 'page',
					'post_name'    => $page_slug,
				)
			);

		}
	}

	/**
	 * Remove proceed to checkout button and replace with proceed to attendee details button.
	 */
	public function replace_proceed_to_checkout_button() {

		if ( is_cart() ) {

			$has_event_product = false;

			foreach ( WC()->cart->get_cart() as $cart_item ) {

				$product  = $cart_item['data'];
				$is_event = $this->is_product_event( $product );

				if ( 'Event' === $is_event ) {

					$has_event_product = true;
					break;
				}
			}

			if ( $has_event_product ) {

				remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
				add_action( 'woocommerce_proceed_to_checkout', array( $this, 'proceed_to_attendee_details_button' ) );

			}
		}
	}

	/**
	 * Add proceed to attendee details button.
	 */
	public function proceed_to_attendee_details_button() {

		echo '<a href="' . esc_url( $this->attendee_page_url ) . '" class="checkout-button button alt wc-forward wp-element-button">Proceed to Attendee Details</a>';
	}

	/**
	 * Do shortcode to display attendee form
	 */
	public function display_attendee_form() {

		if ( ! is_admin() && function_exists( 'WC' ) && WC()->cart && method_exists( WC()->cart, 'get_cart_contents_count' ) ) {

			if ( ! WC()->cart->get_cart_contents_count() ) {

				return '<p>' . __( 'Cart is empty', 'woocommerce-events' ) . '</p>';

			}

			// Get event product attendees.
			$event_attendee_items = $this->fooevents_cart->get_event_attendee_items();

			if ( $event_attendee_items ) {

				$copy_purchaser = get_option( 'globalWooCommerceEventsAddCopyPurchaserDetails', true );

				ob_start();

				$errors    = WC()->session->get( 'fooevents_attendee_errors', array() );
				$prev_post = WC()->session->get( 'fooevents_attendee_POST', array() );

				include $this->config->template_path . 'attendee/' . 'attendee-page.php';

				WC()->session->set( 'fooevents_attendee_errors', array() );
				WC()->session->set( 'fooevents_attendee_POST', array() );

				return ob_get_clean();

			} else {

				// Nothing to capture redirect to checkout.
				wp_redirect( wc_get_checkout_url() );

			}
		}
	}

	/**
	 * Output errors to attendee page.
	 *
	 * @param array $errors Array of errors.
	 */
	public function output_errors( $errors ) {

		if ( ! empty( $errors ) ) {

			echo '<div class="woocommerce-notices-wrapper fooevents-attendee-page-errors">';
			echo '<ul class="woocommerce-error" role="alert">';
			foreach ( $errors as $err ) {

				echo '<li>' . esc_attr( $err ) . '</li>';

			}
			echo '</ul>';
			echo '</div>';

		}
	}

	/**
	 * Save attendee data to cart session.
	 */
	public function save_attendee_data_to_cart() {

		if ( isset( $_POST['fooevents_attendee_nonce'] ) && wp_verify_nonce( $_POST['fooevents_attendee_nonce'], 'fooevents_attendee_details_page' ) && isset( $_POST['fooevents_submit_attendees'] ) && ! empty( $_POST['attendees'] ) ) {

			$errors = array();

			// Validate.
			require_once $this->config->class_path . '/attendee/class-fooevents-attendee-page-validation.php';
			$attendee_validation = new FooEvents_Attendee_Page_Validation( $this->config, $this->fcaf, $this->fb, $this->fs );
			$errors              = $attendee_validation->do_validation();

			foreach ( $_POST['attendees'] as $event_id => $event_item ) {

				foreach ( $event_item as $cart_item_key => $event_attendees ) {

					foreach ( WC()->cart->get_cart() as $key => $cart_item ) {

						if ( (string) $cart_item_key === (string) $key ) {

							WC()->cart->cart_contents[ $key ]['attendees'] = array_map(
								function ( $attendee ) {

									return array(
										'first_name'   => sanitize_text_field( $attendee['first_name'] ?? '' ),
										'last_name'    => sanitize_text_field( $attendee['last_name'] ?? '' ),
										'email'        => sanitize_text_field( $attendee['email'] ?? '' ),
										'telephone'    => sanitize_text_field( $attendee['telephone'] ?? '' ),
										'company'      => sanitize_text_field( $attendee['company'] ?? '' ),
										'designation'  => sanitize_text_field( $attendee['designation'] ?? '' ),
										'custom_field' => $attendee['custom_field'] ?? '',
										'booking'      => $attendee['booking'] ?? '',
										'seating'      => $attendee['seating'] ?? '',
									);
								},
								$event_attendees
							);

							WC()->cart->set_session();

							break;
						}
					}
				}
			}

			if ( empty( $errors ) ) {

				WC()->cart->set_session(); // Save cart data
				wc_add_notice( __( 'Attendee names saved. You can now proceed to checkout.', 'woocommerce' ), 'success' );
				wp_redirect( wc_get_checkout_url() );
				exit();

			} else {

				WC()->session->set( 'fooevents_attendee_errors', $errors );
				WC()->session->set( 'fooevents_attendee_POST', $_POST['attendees'] );
				wp_redirect( $this->attendee_page_url );
				exit();

			}
			exit();

		}
	}

	/**
	 * Store cart attendee data as traditional FooEvents order meta. New WooCommerce checkout support.
	 *
	 * @param object $order the order.
	 */
	public function store_attendee_info_from_cart( $order ) {

		$attendee_info = array();
		$customer_id   = $order->get_user_id();
		$order_id      = $order->get_id();

		foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {

			$product  = $cart_item['data'];
			$quantity = $cart_item['quantity'];
			$is_event = $this->is_product_event( $product );

			if ( ! empty( $cart_item['attendees'] ) && is_array( $cart_item['attendees'] ) ) {

				$attendees     = isset( $cart_item['attendees'] ) ? $cart_item['attendees'] : array();
				$num_attendees = count( $attendees );

				if ( $num_attendees > $quantity ) {

					$attendees = array_slice( $attendees, 0, $quantity );

				}

				$price_incl_tax = wc_get_price_including_tax( $cart_item['data'] );

				$attendee_info[ $cart_item['product_id'] ][ $cart_item_key ] = array(
					'product_id'   => $cart_item['product_id'],
					'variation_id' => $cart_item['variation_id'],
					'variation'    => $cart_item['variation'],
					'product_name' => $cart_item['data']->get_name(),
					'attendees'    => $attendees,
					'price'        => $price_incl_tax,
				);

			} elseif ( $is_event ) {

				$attendees = array();
				for ( $i = 0; $i < $cart_item['quantity']; $i++ ) {

					$attendees[ $i ] = array();

				}

				if ( $this->fb ) {

					$attendees = $this->fb->cater_no_attendee_input( $attendees, $cart_item );

				}

				if ( $this->fs ) {

					$attendees = $this->fs->cater_no_attendee_input( $attendees, $cart_item );

				}

				$attendee_info[ $cart_item['product_id'] ][ $cart_item_key ] = array(
					'product_id'   => $cart_item['product_id'],
					'variation_id' => $cart_item['variation_id'],
					'variation'    => $cart_item['variation'],
					'product_name' => $cart_item['data']->get_name(),
					'attendees'    => $attendees,
					'price'        => $price_incl_tax,
				);

			}
		}

		$order_tickets = array();

		$x = 1;
		foreach ( $attendee_info as $event_id => $event_item ) {

			$y = 1;
			foreach ( $event_item as $cart_item_key => $event ) {

				foreach ( $event['attendees'] as $attendee ) {

					$order_tickets[ $x ][ $y ] = $this->format_order_ticket( $customer_id, $event['product_id'], $order_id, '', $event['variation'], $event['variation_id'], $event['price'], $x, $y, $attendee['first_name'], $attendee['last_name'], $attendee['email'], $attendee['telephone'], $attendee['company'], $attendee['designation'] );

					// Addons.
					if ( $this->fcaf ) {

						$order_tickets[ $x ][ $y ]['WooCommerceEventsCustomAttendeeFields'] = $this->fcaf->format_order_fields( $attendee );

					}

					if ( $this->fb ) {

						$order_tickets[ $x ][ $y ]['WooCommerceEventsBookingOptions'] = $this->fb->format_order_fields( $attendee, $event['product_id'] );

					}

					if ( $this->fs ) {

						$seating = $this->fs->format_order_fields( $attendee, $event['product_id'] );
						$order_tickets[ $x ][ $y ]['WooCommerceEventsSeatingFields'] = $seating['WooCommerceEventsSeatingFields'];

					}

					++$y;

				}
			}
			++$x;
		}

		$order->update_meta_data( 'WooCommerceEventsOrderTickets', $order_tickets );
		$order->save();

		// Clear WooCommerce notices.
		wc_clear_notices();
	}

	/**
	 * Store cart attendee data as traditional FooEvents order meta. Classic checkout support.
	 *
	 * @param int $order_id the order ID.
	 */
	public function store_attendee_info_from_cart_classic_checkout( $order_id ) {

		$order = wc_get_order( $order_id );

		$this->store_attendee_info_from_cart( $order );
	}

	/**
	 * Format attendee data to be stored as order meta.
	 *
	 * @param int    $customer_id the customer ID.
	 * @param int    $product_id the product ID.
	 * @param int    $order_id the order ID.
	 * @param string $ticket_type the ticket type.
	 * @param array  $variations array of ticket variations.
	 * @param int    $variation_id the variation id.
	 * @param string $price the ticket price.
	 * @param int    $x event counter.
	 * @param int    $y ticket counter.
	 * @param string $attendee_name the attendee first name.
	 * @param string $attendee_last_name the attendee last name.
	 * @param string $attendee_email the attendee email.
	 * @param string $attendee_telephone the attendee telephone.
	 * @param string $attendee_company the attendee company.
	 * @param string $attendee_designation the attendee designation.
	 * @param array  $ticket_data ticket data.
	 */
	public function format_order_ticket( $customer_id, $product_id, $order_id, $ticket_type, $variations, $variation_id, $price, $x, $y, $attendee_name = '', $attendee_last_name = '', $attendee_email = '', $attendee_telephone = '', $attendee_company = '', $attendee_designation = '', $ticket_data = array() ) {

		$order = wc_get_order( $order_id );

		$ticket = array();

		$ticket['WooCommerceEventsProductID']           = sanitize_text_field( $product_id );
		$ticket['WooCommerceEventsOrderID']             = sanitize_text_field( $order_id );
		$ticket['WooCommerceEventsTicketType']          = sanitize_text_field( $ticket_type );
		$ticket['WooCommerceEventsStatus']              = 'Unpaid';
		$ticket['WooCommerceEventsCustomerID']          = sanitize_text_field( $customer_id );
		$ticket['WooCommerceEventsAttendeeName']        = sanitize_text_field( $attendee_name );
		$ticket['WooCommerceEventsAttendeeLastName']    = sanitize_text_field( $attendee_last_name );
		$ticket['WooCommerceEventsAttendeeEmail']       = sanitize_text_field( $attendee_email );
		$ticket['WooCommerceEventsAttendeeTelephone']   = sanitize_text_field( $attendee_telephone );
		$ticket['WooCommerceEventsAttendeeCompany']     = sanitize_text_field( $attendee_company );
		$ticket['WooCommerceEventsAttendeeDesignation'] = sanitize_text_field( $attendee_designation );
		$ticket['WooCommerceEventsVariations']          = $variations;
		$ticket['WooCommerceEventsVariationID']         = $variation_id;
		$ticket['WooCommerceEventsPrice']               = wc_price( $price );

		$woocommerce_events_purchaser_first_name = $order->get_billing_first_name();
		$woocommerce_events_purchaser_last_name  = $order->get_billing_last_name();
		$woocommerce_events_purchaser_email      = $order->get_billing_email();
		$woocommerce_events_purchaser_phone      = $order->get_billing_phone();

		$ticket['WooCommerceEventsPurchaserFirstName'] = $woocommerce_events_purchaser_first_name;
		$ticket['WooCommerceEventsPurchaserLastName']  = $woocommerce_events_purchaser_last_name;
		$ticket['WooCommerceEventsPurchaserEmail']     = $woocommerce_events_purchaser_email;
		$ticket['WooCommerceEventsPurchaserPhone']     = $woocommerce_events_purchaser_phone;

		return $ticket;
	}

	/**
	 * If user goes to checkout without filling out attendee details then redirect to attendee page.
	 */
	public function redirect_checkout_if_no_attendees() {

		$event_attendee_items = $this->fooevents_cart->get_event_attendee_items();

		if ( $event_attendee_items ) {

			if ( is_checkout() && ! is_wc_endpoint_url() && ! is_admin() ) {

				$attendees_missing = false;

				foreach ( WC()->cart->get_cart() as $cart_item ) {

					$product  = $cart_item['data'];
					$event_id = $cart_item['product_id'];
					$is_event = $this->is_product_event( $product );

					if ( $is_event && $event_attendee_items[ $event_id ]['capture_attendees'] ) {

						$quantity  = isset( $cart_item['quantity'] ) ? absint( $cart_item['quantity'] ) : 0;
						$attendees = isset( $cart_item['attendees'] ) && is_array( $cart_item['attendees'] ) ? $cart_item['attendees'] : array();

						if ( count( $attendees ) < $quantity ) {

							$attendees_missing = true;
							break;

						}
					}
				}

				if ( $attendees_missing ) {

					wp_redirect( $this->attendee_page_url );
					exit();

				}
			}
		}
	}

	/**
	 * Save attendee data to cart meta.
	 *
	 * @param  object $item cart item.
	 * @param  string $cart_item_key cart item key.
	 * @param  array  $values POST values.
	 * @param  object $order order object.
	 */
	public function save_attendee_data_to_order_items( $item, $cart_item_key, $values, $order ) {

		if ( ! empty( $values['attendees'] ) ) {

			$item->add_meta_data( 'Attendees', $values['attendees'], true );

		}
	}

	/**
	 * Determine if a product is an event.
	 *
	 * @param object $product The product object.
	 */
	private function is_product_event( $product ) {

		$is_event = $product->get_meta( 'WooCommerceEventsEvent' );

		if ( empty( $is_event ) && $product->is_type( 'variation' ) ) {

			$is_event = get_post_meta( $product->get_parent_id(), 'WooCommerceEventsEvent', true );

		}

		return $is_event;
	}

	/**
	 * Test if WooCommerce checkout block is enabled.
	 */
	private function is_checkout_block_enabled() {

		$checkout_page_id = wc_get_page_id( 'checkout' );
		$checkout_content = get_post_field( 'post_content', $checkout_page_id );

		$checkout_block_enabled = 'no';
		if ( has_block( 'woocommerce/checkout', $checkout_content ) ) {

			$checkout_block_enabled = 'yes';

		}

		return $checkout_block_enabled;
	}
}
