<?php
namespace SabaiApps\Directories\Component\WordPressContent\Helper;

use SabaiApps\Directories\Application;

class ContentTypesHelper {
	public function help( Application $application, $force = false ) {
		$cache_id = 'wordpress_content_types_' . $application->IsAdministrator();
		if ( $force
			|| false === ( $content_types = $application->getPlatform()->getCache( $cache_id ) )
		) {
			$application->getPlatform()->setCache( $content_types = $this->_getContentTypes( $application ), $cache_id, 0 );
		}
		return $content_types;
	}

	public function clearCache( Application $application ) {
		$application->getPlatform()->deleteCache( 'wordpress_content_types_' . $application->IsAdministrator() );
	}

	protected function _getContentTypes( Application $application ) {
		$ret              = array(
			'post_types' => array(),
			'taxonomies' => array(),
		);
		$taxonomy_bundles = $taxonomy_to_post_types = array();
		$cap_prefix       = 'drts_entity_';
		foreach ( $application->getModel( 'Directory', 'Directory' )->fetch() as $directory ) {
			$post_bundles   = array();
			$primary_bundle = null;
			foreach ( $application->Entity_Bundles_sort( null, $directory->name ) as $bundle ) {
				if ( $bundle->name === 'product' ) {
					continue;
				}

				if ( ! $application->Entity_BundleTypes( $bundle->type ) ) {
					continue; // check component exists for this bundle type
				}

				if ( $bundle->entitytype_name === 'post' ) {
					$post_bundles[ $bundle->name ] = $bundle->name;
					if ( ! empty( $bundle->info['is_primary'] ) ) {
						$primary_bundle = $bundle->name;
					}
				} elseif ( $bundle->entitytype_name === 'term' ) {
					$taxonomy_bundles[ $bundle->name ] = $bundle->name;
				} elseif ( $bundle->entitytype_name === 'fieldset' ) {
					$post_bundles[ $bundle->name ] = $bundle->name;
				} elseif ( ! empty( $bundle->info['is_primary'] ) ) {
						$primary_bundle = $bundle->name;
				}
			}
			if ( ! isset( $primary_bundle ) ) {
				$application->logError( sprintf( 'No primary bundle found for directory "%s", skipping.', $directory->name ) );
				continue;
			}

			foreach ( $application->Filter( 'wordpress_post_types', $post_bundles ) as $bundle_name ) {
				if ( ! $bundle = $application->Entity_Bundle( $bundle_name ) ) {
					continue;
				}

				$label          = $bundle->getLabel();
				$label_singular = $bundle->getLabel( 'singular' );
				$label_lower    = strtolower( $label );
				$group_label    = $bundle->getGroupLabel();
				$no_title       = ! empty( $bundle->info['no_title'] );
				$public         = ! isset( $bundle->info['public'] ) || ! empty( $bundle->info['public'] ) || ! empty( $bundle->info['is_primary'] );
				$supports       = $no_title ? array( 'author' ) : array( 'author', 'title' );
				$can_add        = $public && $application->Entity_BundleTypeInfo( $bundle->type, 'addable' ) !== false;
				if ( $public ) {
					$supports[] = 'comments';
					$supports[] = 'buddypress-activity';
				}
				if ( ! empty( $bundle->info['wp_post_thumbnail'] ) ) {
					$supports[] = 'thumbnail';
				}
				if ( ! empty( $bundle->info['parent'] ) ) {
					$parent_bundle_name = $bundle->info['parent'];
				} elseif ( ! empty( $bundle->info['parent_field'] ) ) {
					$parent_bundle_name = $primary_bundle;
				} else {
					$parent_bundle_name = null;
				}
				$ret['post_types'][ $bundle->name ] = array(
					'labels'              => $application->Filter(
						'wordpress_post_type_labels',
						array(
							'name'               => $group_label . ' - ' . $label,
							'singular_name'      => $group_label . ' - ' . $label_singular,
							'menu_name'          => empty( $parent_bundle_name ) ? $bundle->component : $label,
							'all_items'          => empty( $parent_bundle_name ) ? $bundle->getLabel( 'all' ) : $label,
							'add_new'            => $label_add = $bundle->getLabel( 'add' ),
							'add_new_item'       => $label_add,
							'edit_item'          => sprintf( __( 'Edit %s', 'directories-pro' ), $label_singular ),
							'new_item'           => sprintf( __( 'New %s', 'directories-pro' ), $label_singular ),
							'view_item'          => sprintf( __( 'View %s', 'directories-pro' ), $label_singular ),
							'search_items'       => sprintf( __( 'Search %s', 'directories-pro' ), $label ),
							'not_found'          => sprintf( __( 'No %s found', 'directories-pro' ), $label_lower, $label ),
							'not_found_in_trash' => sprintf( __( 'No %s found in Trash', 'directories-pro' ), $label_lower, $label ),
							'parent_item_colon'  => empty( $parent_bundle_name ) || ( ! $parent_bundle = $application->Entity_Bundle( $parent_bundle_name ) )
								? ''
								: sprintf( __( 'Parent %s', 'directories-pro' ), $parent_bundle->getLabel( 'singular' ) ),
						),
						array( $bundle )
					),
					'public'              => true,
					'publicly_queryable'  => $public,
					'exclude_from_search' => ! $public,
					'rewrite'             => array(
						'slug'       => $bundle->name,
						'with_front' => false,
					),
					'has_archive'         => false,
					'supports'            => $supports,
					'show_ui'             => ! isset( $bundle->info['system'] ) || ! $bundle->info['system'],
					'show_in_menu'        => ! empty( $bundle->info['is_primary'] )
						? true : ( $bundle->entitytype_name === 'post'
							? ( $directory->type === 'user' ? 'users.php' : 'edit.php?post_type=' . $primary_bundle )
							: false ),
					'show_in_rest'        => $public,
					'show_in_nav_menus'   => $public,
					'parent'              => empty( $bundle->info['parent'] ) ? null : $bundle->info['parent'],
					'drts_group'          => $bundle->group,
				);
				if ( $public ) {
					$ret['post_types'][ $bundle->name ]['capabilities'] = array(
						'read'                   => $cap_prefix . 'read_' . $bundle->name,
						'read_private_posts'     => $cap_prefix . 'read_private_' . $bundle->name,
						'create_posts'           => $cap_prefix . 'create_' . $bundle->name,
						'edit_posts'             => $cap_prefix . 'edit_' . $bundle->name,
						'edit_others_posts'      => $cap_prefix . 'edit_others_' . $bundle->name,
						'publish_posts'          => $cap_prefix . 'publish_' . $bundle->name,
						'delete_posts'           => $cap_prefix . 'delete_' . $bundle->name,
						'delete_private_posts'   => $cap_prefix . 'delete_private_' . $bundle->name,
						'delete_published_posts' => $cap_prefix . 'delete_published_' . $bundle->name,
						'delete_others_posts'    => $cap_prefix . 'delete_others_' . $bundle->name,
						'edit_private_posts'     => $cap_prefix . 'edit_private_' . $bundle->name,
						'edit_published_posts'   => $cap_prefix . 'edit_published_' . $bundle->name,
						'moderate_comments'      => $cap_prefix . 'moderate_comments_' . $bundle->name,
					);
					if ( function_exists( 'buddypress' ) ) {
						$singular                                      = $ret['post_types'][ $bundle->name ]['labels']['singular_name'];
						$ret['post_types'][ $bundle->name ]['labels'] += array(
							'bp_activity_admin_filter'   => str_replace( '%s', $singular, _x( 'New %s published', 'buddypress', 'directories-pro' ) ),
							'bp_activity_front_filter'   => $ret['post_types'][ $bundle->name ]['labels']['name'],
							'bp_activity_new_post'       => str_replace( '%4$s', $singular, _x( '%1$s posted a new <a href="%2$s">%4$s</a>', 'buddypress', 'directories-pro' ) ),
							'bp_activity_new_post_ms'    => str_replace( '%4$s', $singular, _x( '%1$s posted a new <a href="%2$s">%4$s</a>, on the site %3$s', 'buddypress', 'directories-pro' ) ),
							'bp_activity_comments_admin_filter' => $comments_str = str_replace( '%s', $singular, _x( '%s - Comments', 'buddypress', 'directories-pro' ) ),
							'bp_activity_comments_front_filter' => $comments_str,
							'bp_activity_new_comment'    => str_replace( '%4$s', $singular, _x( '%1$s commented on the <a href="%2$s">%4$s</a>', 'buddypress', 'directories-pro' ) ),
							'bp_activity_new_comment_ms' => str_replace( '%4$s', $singular, _x( '%1$s commented on the <a href="%2$s">%4$s</a>, on the site %3$s', 'buddypress', 'directories-pro' ) ),
						);
						$ret['post_types'][ $bundle->name ]['bp_activity'] = array(
							'component_id'      => buddypress()->activity->id,
							'action_id'         => 'new_' . $bundle->name,
							'comment_action_id' => 'new_' . $bundle->name . '_comment',
							'contexts'          => array( 'activity', 'member' ),
							'position'          => 40,
						);
					}
				} elseif ( $can_add ) {
						$ret['post_types'][ $bundle->name ]['capabilities'] = array(
							'read'                   => $cap_prefix . 'create_' . $bundle->name,
							'read_private_posts'     => $cap_prefix . 'create_' . $bundle->name,
							'create_posts'           => $cap_prefix . 'create_' . $bundle->name,
							'publish_posts'          => $cap_prefix . 'create_' . $bundle->name,
							'edit_posts'             => $cap_prefix . 'edit_' . $bundle->name,
							'edit_others_posts'      => $cap_prefix . 'edit_others_' . $bundle->name,
							'edit_private_posts'     => $cap_prefix . 'edit_others_' . $bundle->name,
							'edit_published_posts'   => $cap_prefix . 'edit_' . $bundle->name,
							'delete_posts'           => $cap_prefix . 'delete_' . $bundle->name,
							'delete_others_posts'    => $cap_prefix . 'delete_others_' . $bundle->name,
							'delete_private_posts'   => $cap_prefix . 'delete_others_' . $bundle->name,
							'delete_published_posts' => $cap_prefix . 'delete_' . $bundle->name,
						);
				}
				if ( isset( $ret['post_types'][ $bundle->name ]['capabilities'] ) ) {
					$ret['post_types'][ $bundle->name ]['map_meta_cap']    = true;
					$ret['post_types'][ $bundle->name ]['capability_type'] = $bundle->name;
				}
				if ( ! empty( $bundle->info['taxonomies'] ) ) {
					foreach ( $bundle->info['taxonomies'] as $taxonomy_type => $taxonomy_name ) {
						$taxonomy_to_post_types[ $taxonomy_name ][] = $bundle->name;
					}
				}

				// Let other components modify
				if ( ! $ret['post_types'][ $bundle->name ] = $application->Filter(
					'wordpress_post_type',
					$ret['post_types'][ $bundle->name ],
					array( $bundle )
				) ) {
					unset( $ret['post_types'][ $bundle->name ] );
				}
			}
		}

		if ( ! empty( $taxonomy_to_post_types ) ) {
			foreach ( $taxonomy_bundles as $taxonomy_bundle_name ) {
				if ( ! isset( $taxonomy_to_post_types[ $taxonomy_bundle_name ] )
					|| ( ! $taxonomy_bundle = $application->Entity_Bundle( $taxonomy_bundle_name ) )
				) {
					continue;
				}

				$tax_label          = $taxonomy_bundle->getLabel();
				$tax_label_singular = $taxonomy_bundle->getLabel( 'singular' );
				$tax_label_lower    = strtolower( $tax_label );
				$ret['taxonomies'][ $taxonomy_bundle->type ][ $taxonomy_bundle_name ] = array(
					'post_type'         => $taxonomy_to_post_types[ $taxonomy_bundle_name ],
					'labels'            => $application->Filter(
						'wordpress_taxonomy_labels',
						array(
							'name'              => $group_label . ' - ' . $tax_label,
							'singular_name'     => $group_label . ' - ' . $tax_label_singular,
							'menu_name'         => $tax_label,
							'all_items'         => $taxonomy_bundle->getLabel( 'all' ),
							'add_new_item'      => $taxonomy_bundle->getLabel( 'add' ),
							'new_item_name'     => sprintf( __( 'New %s Name', 'directories-pro' ), $tax_label_singular ),
							'parent_item'       => sprintf( __( 'Parent %s', 'directories-pro' ), $tax_label_singular ),
							'parent_item_colon' => sprintf( __( 'Parent %s:', 'directories-pro' ), $tax_label_singular ),
							'edit_item'         => sprintf( __( 'Edit %s', 'directories-pro' ), $tax_label_singular ),
							'view_item'         => sprintf( __( 'View %s', 'directories-pro' ), $tax_label_singular ),
							'update_item'       => sprintf( __( 'Update %s', 'directories-pro' ), $tax_label_singular ),
							'search_items'      => sprintf( __( 'Search %s', 'directories-pro' ), $tax_label ),
							'not_found'         => sprintf( __( 'No %s found', 'directories-pro' ), $tax_label_lower, $tax_label ),
						),
						array( $taxonomy_bundle )
					),
					'query_var'         => true,
					'public'            => true,
					'show_admin_column' => true,
					'show_in_rest'      => true,
					'rewrite'           => array(
						'slug'       => $taxonomy_bundle_name,
						'with_front' => false,
					),
					'capabilities'      => array(
						'manage_terms' => $cap_prefix . 'manage_' . $taxonomy_bundle_name,
						'edit_terms'   => $cap_prefix . 'edit_' . $taxonomy_bundle_name,
						'delete_terms' => $cap_prefix . 'delete_' . $taxonomy_bundle_name,
						'assign_terms' => $cap_prefix . 'assign_' . $taxonomy_bundle_name,
					),
				);
				if ( ! empty( $taxonomy_bundle->info['is_hierarchical'] ) ) {
					$ret['taxonomies'][ $taxonomy_bundle->type ][ $taxonomy_bundle_name ]['hierarchical'] = true;
				} else {
					$ret['taxonomies'][ $taxonomy_bundle->type ][ $taxonomy_bundle_name ] += array(
						'hierarchical'               => false,
						'popular_items'              => sprintf( __( 'Popular %s', 'directories-pro' ), $tax_label ),
						'separate_items_with_commas' => sprintf( __( 'Separate %s with commas', 'directories-pro' ), $tax_label_lower, $tax_label ),
						'add_or_remove_items'        => sprintf( __( 'Add or remove %s', 'directories-pro' ), $tax_label_lower, $tax_label ),
						'choose_from_most_used'      => sprintf( __( 'Choose from the most used %s', 'directories-pro' ), $tax_label_lower, $tax_label ),
					);
				}

				// Let other components modify
				$ret['taxonomies'][ $taxonomy_bundle->type ][ $taxonomy_bundle_name ] = $application->Filter(
					'wordpress_taxonomy',
					$ret['taxonomies'][ $taxonomy_bundle->type ][ $taxonomy_bundle_name ],
					array( $taxonomy_bundle )
				);
			}
		}

		return $ret;
	}

	public function register( Application $application, $force = false ) {
		$content_types = $this->help( $application, $force );
		$post_types    = $taxonomies = array();
		foreach ( $content_types['post_types'] as $post_type_name => $post_type ) {
			$result = register_post_type( $post_type_name, $post_type );
			if ( is_wp_error( $result ) ) {
				$application->logError( $result->get_error_message() );
				continue;
			}
			$post_types[ $post_type_name ] = array(
				'parent'   => null,
				'children' => array(),
			);
			if ( $post_type['parent'] ) {
				$post_types[ $post_type['parent'] ]['children'][] = $post_type_name;
				$post_types[ $post_type_name ]['parent']          = $post_type['parent'];
			}

			// Prevent WordPress from generating default rewrite rules for this post type
			add_filter(
				$post_type_name . '_rewrite_rules',
				function () {
					return array();
				}
			);
		}
		foreach ( $content_types['taxonomies'] as $taxonomy_type => $_taxonomies ) {
			foreach ( $_taxonomies as $taxonomy_name => $taxonomy ) {
				$post_type_name = $taxonomy['post_type'];
				settype( $post_type_name, 'array' );
				foreach ( array_keys( $post_type_name ) as $i ) {
					if ( ! isset( $post_types[ $post_type_name[ $i ] ] ) ) {
						unset( $post_type_name[ $i ] );
					}
				}
				if ( empty( $post_type_name ) ) {
					continue;
				}

				unset( $taxonomy['post_type'] ); // not required with register_taxonomy
				$result = register_taxonomy( $taxonomy_name, $post_type_name, $taxonomy );
				if ( is_wp_error( $result ) ) {
					$application->logError( $result->get_error_message() );
					continue;
				}
				$taxonomies[ $taxonomy_name ] = $taxonomy_type;

				// Prevent WordPress from generating default rewrite rules for this taxonomy
				add_filter(
					$taxonomy_name . '_rewrite_rules',
					function () {
						return array();
					}
				);
			}
		}

		return array(
			'post_types' => $post_types,
			'taxonomies' => $taxonomies,
		);
	}

	public function registerTemplates( Application $application ) {
		register_block_template(
			'directories-pro/drts-directory-template',
			array(
				'title'       => 'Directories: Directory',
				'description' => __( 'Template for the main page of your directory.', 'directories-pro' ),
				'content'     => $this->_getTemplateContent( 'directory.php' ),
				'plugin'      => 'directories-pro',
				'post_types'  => array( 'page' ),
			)
		);
		register_block_template(
			'directories-pro/drts-post-template',
			array(
				'title'       => 'Directories: Post',
				'description' => __( 'Default template used to display a single post in your directory.', 'directories-pro' ),
				'content'     => $this->_getTemplateContent( 'post.php' ),
				'plugin'      => 'directories-pro',
			)
		);
		register_block_template(
			'directories-pro/drts-term-template',
			array(
				'title'       => 'Directories: Term',
				'description' => __( 'Default template used to display a single taxonomy along with its associated posts.', 'directories-pro' ),
				'content'     => $this->_getTemplateContent( 'term.php' ),
				'plugin'      => 'directories-pro',
			)
		);
		register_block_template(
			'directories-pro/drts-user-template',
			array(
				'title'       => 'Directories: User',
				'description' => __( 'Template for displaying an individual user profile in your user directory.', 'directories-pro' ),
				'content'     => $this->_getTemplateContent( 'user.php' ),
				'plugin'      => 'directories-pro',
			)
		);
	}

	protected function _getTemplateContent( $template, array $args = array() ) {
		extract( $args, EXTR_SKIP );
		ob_start();
		include strpos( $template, '/' ) === 0 ? $template : dirname( __DIR__ ) . '/templates/' . $template;
		return ob_get_clean();
	}
}
