<?php

use EM\Archetypes;

if( !class_exists('EM_Permalinks') ){
	class EM_Permalinks {
		static $em_queryvars = array (
			'event_id',
			'event_slug',
			'em_redirect',
			'recurring_event',
			'recurrence_set',
			'location_id',
			'location_slug',
			'person_id',
			'booking_id',
			'category_id',
			'category_slug',
			'ticket_id',
			'calendar_day',
			'rss',
			'ical',
			'event_archetype',
			'event_categories',
			'event_locations'
		);

		public static function init () {
			add_filter( 'pre_update_option_dbem_events_page', array ( 'EM_Permalinks', 'option_update' ) );
			if ( em_get_option( 'dbem_flush_needed' ) ) {
				add_filter( 'wp_loaded', array (
					'EM_Permalinks',
					'flush'
				) ); //flush after init, in case there are themes adding cpts etc.
			}
			add_filter( 'rewrite_rules_array', array ( 'EM_Permalinks', 'rewrite_rules_array' ) );
			add_filter( 'query_vars', array ( 'EM_Permalinks', 'query_vars' ) );
			add_action( 'parse_query', array ( 'EM_Permalinks', 'init_objects' ), 1 );
			add_action( 'parse_query', array ( 'EM_Permalinks', 'redirection' ), 1 );
			if ( !defined( 'EM_EVENT_SLUG' ) ) {
				define( 'EM_EVENT_SLUG', 'event' );
			}
			if ( !defined( 'EM_LOCATION_SLUG' ) ) {
				define( 'EM_LOCATION_SLUG', 'location' );
			}
			if ( !defined( 'EM_LOCATIONS_SLUG' ) ) {
				define( 'EM_LOCATIONS_SLUG', 'locations' );
			}
			if ( !defined( 'EM_CATEGORY_SLUG' ) ) {
				define( 'EM_CATEGORY_SLUG', 'category' );
			}
			if ( !defined( 'EM_CATEGORIES_SLUG' ) ) {
				define( 'EM_CATEGORIES_SLUG', 'categories' );
			}
			add_filter( 'post_type_archive_link', array ( 'EM_Permalinks', 'post_type_archive_link' ), 10, 2 );

			add_action( 'template_redirect', [ static::class, 'handle_converted_repeating_404_redirects' ], 10 );
		}

		public static function flush () {
			global $wp_rewrite;
			$wp_rewrite->flush_rules();
			update_option( 'dbem_flush_needed', 0 );
		}

		public static function post_type_archive_link ( $link, $post_type ) {
			if ( $post_type == EM_POST_TYPE_EVENT ) {
				if ( em_get_option( 'dbem_events_page' ) ) {
					$new_link = get_permalink( em_get_option( 'dbem_events_page' ) );
				}
			}
			if ( $post_type == EM_POST_TYPE_LOCATION ) {
				if ( em_get_option( 'dbem_locations_page' ) ) {
					$new_link = get_permalink( em_get_option( 'dbem_locations_page' ) );
				}
			}
			if ( !empty( $new_link ) ) {
				$link = $new_link;
			}

			return $link;
		}

		/**
		 * will redirect old links to new link structures.
		 */
		public static function redirection () {
			global $wpdb, $wp_query;
			if ( is_object( $wp_query ) && $wp_query->get( 'em_redirect' ) ) {
				//is this a querystring url?
				if ( $wp_query->get( 'event_slug' ) ) {
					$event = $wpdb->get_row( $wpdb->prepare( 'SELECT event_id, post_id FROM ' . EM_EVENTS_TABLE . " WHERE event_slug=%s AND (blog_id=%d OR blog_id IS NULL OR blog_id=0)", $wp_query->get( 'event_slug' ), get_current_blog_id() ), ARRAY_A );
					if ( !empty( $event ) ) {
						$EM_Event = em_get_event( $event['event_id'] );
						$url = get_permalink( $EM_Event->post_id );
					}
				} elseif ( $wp_query->get( 'location_slug' ) ) {
					$location = $wpdb->get_row( $wpdb->prepare( 'SELECT location_id, post_id FROM ' . EM_LOCATIONS_TABLE . " WHERE location_slug=%s AND (blog_id=%d OR blog_id IS NULL OR blog_id=0)", $wp_query->get( 'location_slug' ), get_current_blog_id() ), ARRAY_A );
					if ( !empty( $location ) ) {
						$EM_Location = em_get_location( $location['location_id'] );
						$url = get_permalink( $EM_Location->post_id );
					}
				} elseif ( $wp_query->get( 'category_slug' ) ) {
					$url = get_term_link( $wp_query->get( 'category_slug' ), EM_TAXONOMY_CATEGORY );
				}
				if ( !empty( $url ) && is_string( $url ) ) {
					wp_safe_redirect( $url, 301 );
					exit();
				}
			}
		}

		// Adding a new rule
		public static function rewrite_rules_array ( $rules ) {
			global $wpdb;
			//get the slug of the event page
			$events_page_id = em_get_option( 'dbem_events_page' );
			$events_page = get_post( $events_page_id );
			$em_rules = array ();
			if ( is_object( $events_page ) ) {
				$events_slug = urldecode( preg_replace( '/\/$/', '', str_replace( trailingslashit( home_url() ), '', get_permalink( $events_page_id ) ) ) );
				$events_slug = ( !empty( $events_slug ) ) ? trailingslashit( $events_slug ) : $events_slug;
				$events_pagename = trim( $events_slug, '/' );
				$em_rules[ $events_slug . '(\d{4}-\d{2}-\d{2})$' ] = 'index.php?pagename=' . $events_pagename . '&calendar_day=$matches[1]'; //event calendar date search
				if ( $events_page_id != em_get_option( 'page_on_front' ) && EM_POST_TYPE_EVENT_SLUG != $events_slug ) { //ignore this rule if events page is the home page
					$em_rules[ $events_slug . 'rss/?$' ] = 'index.php?post_type=' . EM_POST_TYPE_EVENT . '&feed=feed'; //rss page
					$em_rules[ $events_slug . 'feed/?$' ] = 'index.php?post_type=' . EM_POST_TYPE_EVENT . '&feed=feed'; //compatible rss page
				}
				if ( EM_POST_TYPE_EVENT_SLUG . '/' == $events_slug ) { //won't apply on homepage
					//make sure we hard-code rewrites for child pages of events
					$child_posts = $wpdb->get_results( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_parent={$events_page->ID} AND post_type='page' AND post_status='publish'" );
					foreach ( $child_posts as $child_post ) {
						$em_rules[ $events_slug . urldecode( $child_post->post_name ) . '/?$' ] = 'index.php?page_id=' . $child_post->ID; //single event booking form with slug    //check if child page has children
						$grandchildren = $wpdb->get_results( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_parent={$child_post->ID} AND post_type='page' AND post_status='publish'" );
						if ( count( $grandchildren ) != 0 ) {
							foreach ( $grandchildren as $grandchild ) {
								$em_rules[ $events_slug . urldecode( $child_post->post_name ) . '/' . urldecode( $grandchild->post_name ) . '/?$' ] = 'index.php?page_id=' . $grandchild->ID;
							}
						}
					}
				} elseif ( empty( $events_slug ) ) { //hard code homepage child pages
					$child_posts = $wpdb->get_results( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_parent={$events_page->ID} AND post_type='page' AND post_status='publish'" );
					foreach ( $child_posts as $child_post ) {
						$em_rules[ $events_page->post_name . '/' . urldecode( $child_post->post_name ) . '/?$' ] = 'index.php?page_id=' . $child_post->ID; //single event booking form with slug    //check if child page has children
						$grandchildren = $wpdb->get_results( "SELECT ID, post_name FROM {$wpdb->posts} WHERE post_parent={$child_post->ID} AND post_type='page' AND post_status='publish'" );
						if ( count( $grandchildren ) != 0 ) {
							foreach ( $grandchildren as $grandchild ) {
								$em_rules[ $events_slug . urldecode( $child_post->post_name ) . '/' . urldecode( $grandchild->post_name ) . '/?$' ] = 'index.php?page_id=' . $grandchild->ID;
							}
						}
					}
				}
				//global links hard-coded
				if ( EM_MS_GLOBAL && !get_site_option( 'dbem_ms_global_events_links', true ) ) {
					//MS Mode has slug also for global links
					$em_rules[ $events_slug . get_site_option( 'dbem_ms_events_slug', EM_EVENT_SLUG ) . '/(.+)$' ] = 'index.php?pagename=' . $events_pagename . '&em_redirect=1&event_slug=$matches[1]'; //single event from subsite
				}
				//add redirection for backwards compatability
				$em_rules[ $events_slug . EM_EVENT_SLUG . '/(.+)$' ] = 'index.php?pagename=' . $events_pagename . '&em_redirect=1&event_slug=$matches[1]'; //single event
				$em_rules[ $events_slug . EM_LOCATION_SLUG . '/(.+)$' ] = 'index.php?pagename=' . $events_pagename . '&em_redirect=1&location_slug=$matches[1]'; //single location page
				$em_rules[ $events_slug . EM_CATEGORY_SLUG . '/(.+)$' ] = 'index.php?pagename=' . $events_pagename . '&em_redirect=1&category_slug=$matches[1]'; //single category page slug
				//add a rule that ensures that the events page is found and used over other pages
				$em_rules[ trim( $events_slug, '/' ) . '/?$' ] = 'index.php?pagename=' . $events_pagename;
			} else {
				$events_slug = EM_POST_TYPE_EVENT_SLUG;
				$em_rules[ $events_slug . '/(\d{4}-\d{2}-\d{2})$' ] = 'index.php?post_type=' . EM_POST_TYPE_EVENT . '&calendar_day=$matches[1]'; //event calendar date search
				$em_rules[ $events_slug . '/(\d{4}-\d{2}-\d{2})/page/?([0-9]{1,})/?$' ] = 'index.php?post_type=' . EM_POST_TYPE_EVENT . '&calendar_day=$matches[1]&paged=$matches[2]'; //event calendar date search paged
				if ( em_get_option( 'dbem_rsvp_enabled' ) ) {
					if ( !em_get_option( 'dbem_my_bookings_page' ) || !is_object( get_post( em_get_option( 'dbem_my_bookings_page' ) ) ) ) { //only added if bookings page isn't assigned
						$em_rules[ $events_slug . '/my\-bookings$' ] = 'index.php?post_type=' . EM_POST_TYPE_EVENT . '&bookings_page=1'; //page for users to manage bookings
					}
				}
				//check for potentially conflicting posts with the same slug as events
				$conflicting_posts = get_posts( array (
					'name' => EM_POST_TYPE_EVENT_SLUG,
					'post_type' => 'any',
					'numberposts' => 0
				) );
				if ( count( $conflicting_posts ) > 0 ) { //won't apply on homepage
					foreach ( $conflicting_posts as $conflicting_post ) {
						//make sure we hard-code rewrites for child pages of events
						$child_posts = get_posts( array (
							'post_type' => 'any',
							'post_parent' => $conflicting_post->ID,
							'numberposts' => 0
						) );
						foreach ( $child_posts as $child_post ) {
							$em_rules[ EM_POST_TYPE_EVENT_SLUG . '/' . urldecode( $child_post->post_name ) . '/?$' ] = 'index.php?page_id=' . $child_post->ID; //single event booking form with slug
							//check if child page has children
							$grandchildren = get_pages( 'child_of=' . $child_post->ID );
							if ( count( $grandchildren ) != 0 ) {
								foreach ( $grandchildren as $grandchild ) {
									$em_rules[ $events_slug . urldecode( $child_post->post_name ) . '/' . urldecode( $grandchild->post_name ) . '/?$' ] = 'index.php?page_id=' . $grandchild->ID;
								}
							}
						}
					}
				}
			}
			//Check the event category and tags pages, because if we're overriding the pages and they're not within the Events page hierarchy it may 404
			//if taxonomy base permalink is same as page permalink
			foreach ( array ( 'tags', 'categories' ) as $taxonomy_name ) {
				if ( em_get_option( 'dbem_' . $taxonomy_name . '_enabled' ) ) {
					$taxonomy_page_id = em_get_option( 'dbem_' . $taxonomy_name . '_page' );
					$taxonomy_page = get_post( $taxonomy_page_id );
					if ( is_object( $taxonomy_page ) ) {
						//we are using a categories page, so we add it to permalinks if it's not a parent of the events page
						if ( !is_object( $events_page ) || !in_array( $events_page->ID, get_post_ancestors( $taxonomy_page_id ) ) ) {
							$taxonomy_slug = urldecode( preg_replace( '/\/$/', '', str_replace( trailingslashit( home_url() ), '', get_permalink( $taxonomy_page_id ) ) ) );
							$taxonomy_slug = ( !empty( $taxonomy_slug ) ) ? trailingslashit( $taxonomy_slug ) : $taxonomy_slug;
							$em_rules[ trim( $taxonomy_slug, '/' ) . '/?$' ] = 'index.php?pagename=' . trim( $taxonomy_slug, '/' );
						}
					}
				}
			}
			$em_rules = apply_filters( 'em_rewrite_rules_array_events', $em_rules, $events_slug );
			//make sure there's no page with same name as archives, that should take precedence as it can easily be deleted wp admin side
			$em_query = new WP_Query( array ( 'pagename' => EM_POST_TYPE_EVENT_SLUG ) );
			if ( $em_query->have_posts() ) {
				$em_rules[ trim( EM_POST_TYPE_EVENT_SLUG, '/' ) . '/?$' ] = 'index.php?pagename=' . trim( EM_POST_TYPE_EVENT_SLUG, '/' );
				wp_reset_postdata();
			}
			//make sure there's no page with same name as archives, that should take precedence as it can easily be deleted wp admin side
			$em_query = new WP_Query( array ( 'pagename' => EM_POST_TYPE_LOCATION_SLUG ) );
			if ( $em_query->have_posts() ) {
				$em_rules[ trim( EM_POST_TYPE_LOCATION_SLUG, '/' ) . '/?$' ] = 'index.php?pagename=' . trim( EM_POST_TYPE_LOCATION_SLUG, '/' );
				wp_reset_postdata();
			}
			//If in MS global mode and locations are linked on same site
			if ( EM_MS_GLOBAL && !get_site_option( 'dbem_ms_global_locations_links', true ) ) {
				$locations_page_id = em_get_option( 'dbem_locations_page' );
				$locations_page = get_post( $locations_page_id );
				if ( is_object( $locations_page ) ) {
					$locations_slug = preg_replace( '/\/$/', '', str_replace( trailingslashit( home_url() ), '', get_permalink( $locations_page_id ) ) );
					$em_rules[ $locations_slug . '/' . get_site_option( 'dbem_ms_locations_slug', EM_LOCATION_SLUG ) . '/(.+)$' ] = 'index.php?pagename=' . trim( $locations_slug, '/' ) . '&location_slug=$matches[1]'; //single event booking form with slug
				}
			}
			// add ical CPT endpoints
			if ( em_get_option( 'dbem_locations_enabled' ) ) {
				$em_rules[ EM_POST_TYPE_LOCATION_SLUG . "/([^/]+)/ical/?$" ] = 'index.php?' . EM_POST_TYPE_LOCATION . '=$matches[1]&ical=1';
			}
			// add ical taxonomy endpoints
			$taxonomies = EM_Object::get_taxonomies();
			foreach ( $taxonomies as $tax_arg => $taxonomy_info ) {
				//set the dynamic rule for this taxonomy
				$em_rules[ $taxonomy_info['slug'] . "/(.+)/ical/?$" ] = 'index.php?' . $taxonomy_info['query_var'] . '=$matches[1]&ical=1';
			}
			// add ical endpoint for archetypes showing all events of archetype (similar to events.ics)
			foreach ( EM\Archetypes::get_cpts( [], ['event','types'] ) as $cpt ) {
				$archetype = EM\Archetypes::get( $cpt );
				$em_rules[ $archetype['slug'] . "/ical/?$" ] = 'index.php?ical=1&event_archetype=' . $cpt;
			}
			// add ical endpoint for events (last in case of subdierctory overlap
			foreach ( EM\Archetypes::get_cpts( [], ['event','types'] ) as $cpt ) {
				$archetype = EM\Archetypes::get( $cpt );
				$em_rules[ $archetype['slug'] . "/(.+)/ical/?$" ] = 'index.php?' . $cpt . '=$matches[1]&ical=1&&event_archetype=' . $cpt;
			}
			//add RSS location CPT endpoint
			if ( em_get_option( 'dbem_locations_enabled' ) ) {
				$em_rules[ EM_POST_TYPE_LOCATION_SLUG . "/([^/]+)/rss/?$" ] = 'index.php?' . EM_POST_TYPE_LOCATION . '=$matches[1]&rss=1';
			}
			$em_rules = apply_filters( 'em_rewrite_rules_array', $em_rules );

			return $em_rules + $rules;
		}

		/**
		 * deprecated, use get_post_permalink() from now on or the output function with a placeholder
		 * Generate a URL. Pass each section of a link as a parameter, e.g. EM_Permalinks::url('event',$event_id); will create an event link.
		 * @return string
		 */
		public static function url () {
			global $wp_rewrite;
			$args = func_get_args();
			$em_uri = get_permalink( em_get_option( "dbem_events_page" ) ); //PAGE URI OF EM
			if ( $wp_rewrite->using_permalinks() /*&& !defined('EM_DISABLE_PERMALINKS')*/ ) {
				$event_link = trailingslashit( trailingslashit( $em_uri ) . implode( '/', $args ) );
			}

			return $event_link;
		}

		/**
		 * checks if the events page has changed, and sets a flag to flush wp_rewrite.
		 *
		 * @param mixed $val
		 *
		 * @return mixed
		 */
		public static function option_update ( $val ) {
			if ( em_get_option( 'dbem_events_page' ) != $val ) {
				update_option( 'dbem_flush_needed', 1 );
			}

			return $val;
		}

		// Adding the id var so that WP recognizes it
		public static function query_vars ( $vars ) {
			foreach ( self::$em_queryvars as $em_queryvar ) {
				array_push( $vars, $em_queryvar );
			}

			return $vars;
		}

		/**
		 * Not the "WP way" but for now this'll do!
		 * This function tricks WP into thinking an EM static home page is just a page so that query_vars don't prevent the home page from showing properly.
		 * This is an old problem described here : https://core.trac.wordpress.org/ticket/25143
		 * Since we use these query vars in other areas and need to allow home page static settings to work, this connects the two sides so they can co-exist in different environments
		 */
		public static function init_objects () {
			global $wp_rewrite, $wp_query;
			//check some homepage conditions
			$events_page_id = em_get_option( 'dbem_events_page' );
			if ( is_object( $wp_query ) && $wp_query->is_home && !$wp_query->is_posts_page && 'page' == em_get_option( 'show_on_front' ) && em_get_option( 'page_on_front' ) == $events_page_id ) {
				// comment long after this is written - pretty sure this prevents seach query and pagination issues on the home page when an event page is set as the home static page removing this causes issues with searches and pagination
				$wp_query->is_page = true;
				$wp_query->is_home = false; // WP will not technically expect this to be the home page, but the front page only
				$wp_query->query_vars['page_id'] = $events_page_id;
			}
			if ( is_object( $wp_query ) && is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) {
				foreach ( self::$em_queryvars as $em_queryvar ) {
					if ( $wp_query->get( $em_queryvar ) ) {
						$_REQUEST[ $em_queryvar ] = $wp_query->get( $em_queryvar );
					}
				}
			}
			//dirty rss condition
			if ( !empty( $_REQUEST['rss'] ) ) {
				$_REQUEST['rss_main'] = 'main';
			}
		}

		/**
		 * Handle 404s for deleted event posts by redirecting to unified page
		 */
		public static function handle_converted_repeating_404_redirects () {
			// Only run on 404 pages
			if ( !is_404() ) {
				return;
			}
			global $wpdb;
			// Get the requested URL path
			$request_path = trim( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
			$path_parts = explode( '/', $request_path );

			// Check if this looks like it might be an event post
			// Assuming your events have URLs like /events/event-slug/
			$events_base = EM_POST_TYPE_EVENT_SLUG; // Change this if your events use a different base
			if ( count( $path_parts ) >= 2 && $path_parts[0] === $events_base ) {
				$potential_slug = end( $path_parts );

				// Check if this slug exists in postmeta or another custom table where you store old slugs
				$query = $wpdb->prepare( "SELECT event_id FROM " . EM_EVENTS_TABLE . " WHERE event_slug = %s", $potential_slug );
				$event_id = $wpdb->get_var( $query );
				if ( $event_id ) {
					// Get the unified page URL
					$EM_Event = em_get_event( $event_id );
					if ( $EM_Event->is_recurrence() ) {
						// Perform 302 redirect
						wp_redirect( $EM_Event->get_recurring_event()->get_permalink(), 302 );
						exit();
					}
				}
			}
		}
	}
	EM_Permalinks::init();
}

//Specific links that aren't generated by objects

/**
 * returns the url of the my bookings page, depending on the settings page and if BP is installed.
 * @return string
 */
function em_get_my_bookings_url(){
	global $bp, $wp_rewrite;
	// @todo add filter for bookings url, remove bp condition and add it to bp-em-core.php
	if( !empty($bp->events->link) ){
		//get member url
		return $bp->events->link.'attending/';
	}elseif( em_get_option('dbem_my_bookings_page') ){
		return get_permalink(em_get_option('dbem_my_bookings_page'));
	}else{
		if( $wp_rewrite->using_permalinks() && !defined('EM_DISABLE_PERMALINKS') ){
			return trailingslashit(EM_URI)."my-bookings/";
		}else{
			return preg_match('/\?/',EM_URI) ? EM_URI.'&bookings_page=1':EM_URI.'?bookings_page=1';
		}
	}
}

/**
 * Gets the admin URL for editing events. If called from front-end and there's a front-end edit events page, that will be
 * returned, otherwise a url to the dashboard will be returned.
 */
function em_get_events_admin_url( $archetype = null ){
	$archetype = $archetype ?? Archetypes::get_current();
    $admin_url = admin_url('edit.php?post_type='.$archetype);
    if( !is_admin() ){
        if( em_get_option('dbem_edit_events_page') ){
            $admin_url = get_permalink(em_get_option( 'dbem_edit_events_page' ));
        }
    }
    return apply_filters('em_get_events_admin_url', $admin_url);
}
