<?php
/**
 * Content Class
 *
 * @package errigal
 * @since 1.1.0
 */

namespace Errigal\Content;

defined( 'ABSPATH' ) || exit;

use Errigal\Constant\{
	Errigal_Content_Class as Content_Class,
	Errigal_Content_Hook as Content_Hook,
	Errigal_Html_Attr as Html_Attr,
	Errigal_Html_Option as Html_Option,
	Errigal_Html_Tag as Html_Tag,
	Errigal_Shared_Class as Shared_Class,
};
use Errigal\Shared\{
	Errigal_Html_Builder as Html_Builder,
	Errigal_Query as Query,
	Errigal_Utility as Utility,
	Errigal_Validator as Validator,
};
use WP_Post;
use WP_Term;

/**
 * This class is in charge of providing content settings and functions.
 *
 * @since 1.1.0
 */
class Errigal_Content {
	/**
	 * Attachment metadata: width.
	 *
	 * @since 1.2.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/wp_get_attachment_metadata/
	 *
	 * @var string
	 */
	public const ATTACHMENT_WIDTH = 'width';

	/**
	 * Attachment metadata: height.
	 *
	 * @since 1.2.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/wp_get_attachment_metadata/
	 *
	 * @var string
	 */
	public const ATTACHMENT_HEIGHT = 'height';

	/**
	 * Attachment size: full.
	 *
	 * @since 1.2.0
	 *
	 * @link https://developer.wordpress.org/reference/hooks/image_size_names_choose/
	 *
	 * @var string
	 */
	public const ATTACHMENT_SIZE_FULL = 'full';

	/**
	 * Thumbnail arg: post.
	 *
	 * @since 1.1.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail/
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail_url/
	 *
	 * @var string
	 */
	public const THUMBNAIL_POST = 'post';

	/**
	 * Thumbnail arg: size.
	 *
	 * @since 1.1.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail/
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail_url/
	 *
	 * @var string
	 */
	public const THUMBNAIL_SIZE = 'size';

	/**
	 * Thumbnail arg: attr: loading (HTML <img> loading Attribute).
	 *
	 * @since 1.1.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail/
	 *
	 * @var string
	 */
	public const THUMBNAIL_LOADING = 'loading';

	/**
	 * Thumbnail arg: should_show_background_image.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	public const THUMBNAIL_SHOULD_SHOW_BACKGROUND_IMAGE = 'should_show_background_image';

	/**
	 * Thumbnail arg: should_include_link.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	public const THUMBNAIL_SHOULD_INCLUDE_LINK = 'should_include_link';

	/**
	 * Template: Page: No sidebar.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	protected const TEMPLATE_PAGE_NO_SIDEBAR = 'templates/no-sidebar-page.php';

	/**
	 * Template: Post: No sidebar.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	protected const TEMPLATE_POST_NO_SIDEBAR = 'templates/no-sidebar-post.php';

	/**
	 * Thumbnail arg: attr: class (HTML class Attribute).
	 *
	 * @since 1.1.0
	 *
	 * @link https://developer.wordpress.org/reference/functions/get_the_post_thumbnail/
	 *
	 * @var string
	 */
	private const THUMBNAIL_CLASS = 'class';

	/**
	 * Determines whether current user can edit current content.
	 *
	 * @since 1.1.0
	 *
	 * @return bool
	 */
	public static function can_edit() {
		return current_user_can( 'edit_post', get_the_ID() );
	}

	/**
	 * Determines whether pinned sign can be displayed.
	 *
	 * @since 1.2.0
	 *
	 * @return bool
	 */
	public static function can_show_pinned_sign() {
		return is_sticky() &&
			Validator::has_string_list_item( get_post_class(), Shared_Class::STICKY );
	}

	/**
	 * Gets total pages.
	 *
	 * @since 1.1.0
	 *
	 * @global int $numpages Number of pages in post.
	 *
	 * @return int
	 */
	public static function get_total_pages() {
		global $numpages;

		if ( ! isset( $numpages ) || ! is_singular() || ! is_int( $numpages ) ) {
			return 0;
		}

		return $numpages;
	}

	/**
	 * Gets current page number.
	 *
	 * @since 1.1.0
	 *
	 * @global int $page Page number of single post.
	 *
	 * @return int
	 */
	public static function get_current_page_number() {
		global $page;

		if ( ! isset( $page ) || ! is_singular() || ! is_int( $page ) ) {
			return 0;
		}

		return $page;
	}

	/**
	 * Gets entry content classes.
	 *
	 * @since 1.1.0
	 *
	 * @return string[]
	 */
	public static function get_entry_content_classes() {
		/**
		 * Filters entry content classes.
		 *
		 * @since 1.1.0
		 *
		 * @param string[] $classes Entry content class names.
		 */
		$classes = apply_filters(
			Content_Hook::ENTRY_CONTENT_CLASSES,
			array(
				Content_Class::ENTRY_CONTENT,
			)
		);

		return Utility::sanitise_classes( $classes );
	}

	/**
	 * Gets post parent ID.
	 *
	 * @since 1.2.0
	 *
	 * @global WP_Post $post Global post object.
	 *
	 * @return int|false
	 */
	public static function get_post_parent_id() {
		global $post;

		if ( ! isset( $post ) || ! self::is_wp_post( $post ) ) {
			return false;
		}

		return wp_get_post_parent_id( $post );
	}

	/**
	 * Gets post thumbnail.
	 *
	 * @since 1.0.0
	 *
	 * @param string $class_name Class for <figure> element.
	 * @param array  $args {
	 *     Optional. Associative array of arguments for post thumbnail. Default empty array.
	 *
	 *     @type int|WP_Post $post_object                   Post ID or WP_Post object. Default global `$post`.
	 *     @type string|int[] $size                         Image size. Accepts any registered image size name, or an array of
	 *                                                      width and height values in pixels (in that order). Default 'post-thumbnail'.
	 *     @type string|false $loading                      The 'loading' attribute value. Passing a value of false
	 *                                                      will result in the attribute being omitted for the image.
	 *                                                      Defaults to 'lazy', depending on wp_lazy_loading_enabled().
	 *     @type bool         $should_show_background_image Whether to use IE workaround. Default true.
	 *     @type bool         $should_include_link          Whether to include link to post. Default true.
	 * }
	 * @return string
	 */
	public static function get_post_thumbnail( $class_name, $args = array() ) {
		if (
			! Validator::is_non_empty_string( $class_name ) ||
			! is_array( $args )
		) {
			return '';
		}

		$args = wp_parse_args(
			$args,
			array(
				self::THUMBNAIL_POST                => null,
				self::THUMBNAIL_SIZE                => 'post-thumbnail',
				self::THUMBNAIL_LOADING             => false,
				self::THUMBNAIL_SHOULD_SHOW_BACKGROUND_IMAGE => true,
				self::THUMBNAIL_SHOULD_INCLUDE_LINK => true,
			)
		);

		$post_object         = $args[ self::THUMBNAIL_POST ];
		$should_include_link = $args[ self::THUMBNAIL_SHOULD_INCLUDE_LINK ];

		if ( ! self::can_show_post_thumbnail( $post_object ) ) {
			return '';
		}

		$size                         = $args[ self::THUMBNAIL_SIZE ];
		$loading                      = $args[ self::THUMBNAIL_LOADING ];
		$should_show_background_image = $args[ self::THUMBNAIL_SHOULD_SHOW_BACKGROUND_IMAGE ];

		if (
			! Validator::is_non_empty_string( $size ) ||
			! ( is_bool( $loading ) || is_string( $loading ) )
		) {
			return '';
		}

		$html_builder   = Html_Builder::create();
		$post_thumbnail = self::is_ie() && Validator::is_true( $should_show_background_image )
			? $html_builder->create_div(
				array(
					Html_Option::ATTRS => array(
						Html_Attr::CLASS_NAME => Content_Class::POST_THUMBNAIL,
						Html_Attr::STYLE      => sprintf(
							'background-image: url(%s);',
							esc_url( get_the_post_thumbnail_url( $post_object, $size, ) )
						),
					),
				)
			)->get_element()
			: get_the_post_thumbnail(
				$post_object,
				$size,
				array(
					Html_Attr::CLASS_NAME => Utility::get_class( Content_Class::POST_THUMBNAIL ),
					Html_Attr::LOADING    => $loading,
				)
			);

		if ( ! Validator::is_non_empty_string( $post_thumbnail ) ) {
			return '';
		}

		return $html_builder->create_figure(
			array(
				Html_Option::ATTRS => array(
					Html_Attr::CLASS_NAME => $class_name,
				),
			)
		)->get_element(
			Validator::is_true( $should_include_link )
				? $html_builder->create_a(
					array(
						Html_Option::ATTRS => array(
							Html_Attr::HREF       => get_the_permalink(),
							Html_Attr::ARIA_LABEL => get_the_title(),
						),
					)
				)->get_element( $post_thumbnail )
				: $post_thumbnail,
		);
	}

	/**
	 * Renders post thumbnail.
	 *
	 * @since 1.1.0
	 *
	 * @param string $class_name Class for <figure> element.
	 * @param array  $args {
	 *     Optional. Associative array of arguments for post thumbnail. Default empty array.
	 *
	 *     @type int|WP_Post $post_object                   Post ID or WP_Post object. Default global `$post`.
	 *     @type string|int[] $size                         Image size. Accepts any registered image size name, or an array of
	 *                                                      width and height values in pixels (in that order). Default 'post-thumbnail'.
	 *     @type string|false $loading                      The 'loading' attribute value. Passing a value of false
	 *                                                      will result in the attribute being omitted for the image.
	 *                                                      Defaults to 'lazy', depending on wp_lazy_loading_enabled().
	 *     @type bool         $should_show_background_image Whether to use IE workaround. Default true.
	 *     @type bool         $should_include_link          Whether to include link to post. Default true.
	 * }
	 * @return void
	 */
	public static function render_post_thumbnail( $class_name, $args = array() ) {
		echo wp_kses_post( self::get_post_thumbnail( $class_name, $args ) );
	}

	/**
	 * Determines whether browser is Internet Explorer.
	 *
	 * @since 1.1.0
	 *
	 * @global bool $is_IE Whether browser is Internet Explorer.
	 *
	 * @return bool
	 */
	public static function is_ie() {
		global $is_IE;

		return isset( $is_IE ) && Validator::is_true( $is_IE );
	}

	/**
	 * Determines whether current post has been modified since it was published.
	 *
	 * @since 1.2.0
	 *
	 * @return bool
	 */
	public static function is_modified() {
		return get_the_time( 'U' ) !== get_the_modified_time( 'U' );
	}

	/**
	 * Determines whether current post uses no sidebar template.
	 *
	 * @since 1.0.0
	 *
	 * @return bool
	 */
	public static function is_no_sidebar_post() {
		/**
		 * Filters is no sidebar post.
		 *
		 * @since 1.1.0
		 *
		 * @param bool $is_no_sidebar_post Whether current post uses no sidebar template.
		 */
		$is_no_sidebar_post = apply_filters(
			Content_Hook::IS_NO_SIDEBAR_POST,
			is_page_template(
				array(
					self::TEMPLATE_PAGE_NO_SIDEBAR,
					self::TEMPLATE_POST_NO_SIDEBAR,
				)
			)
		);

		return Validator::is_true( $is_no_sidebar_post );
	}

	/**
	 * Determines whether current post has multiple pages.
	 *
	 * @since 1.1.0
	 *
	 * @global bool $multipage Whether current post has multiple pages.
	 *
	 * @return bool
	 */
	public static function is_paginated() {
		global $multipage;

		return isset( $multipage ) && is_singular() && (bool) $multipage;
	}

	/**
	 * Determines whether $post_object is instance of WP_Post.
	 *
	 * @since 1.1.0
	 *
	 * @param WP_Post $post_object Post object.
	 * @return bool
	 */
	public static function is_wp_post( $post_object ) {
		return $post_object instanceof WP_Post;
	}

	/**
	 * Determines whether $term_object is instance of WP_Term.
	 *
	 * @since 1.1.0
	 *
	 * @param WP_Term $term_object Term object.
	 * @return bool
	 */
	public static function is_wp_term( $term_object ) {
		return $term_object instanceof WP_Term;
	}

	/**
	 * Determines whether content has h1 heading.
	 *
	 * @since 1.1.0
	 *
	 * @global WP_Post $post Global post object.
	 *
	 * @return bool
	 */
	public static function has_h1_heading() {
		global $post;

		if ( ! isset( $post ) || ! self::is_wp_post( $post ) ) {
			return false;
		}

		$content = $post->post_content;

		return Validator::string_contains( $content, '<' . Html_Tag::H1 );
	}

	/**
	 * Determines whether current post type supports categories.
	 *
	 * @since 1.2.0
	 *
	 * @return bool
	 */
	public static function has_category_support() {
		return is_object_in_taxonomy( get_post_type(), Query::CATEGORY );
	}

	/**
	 * Determines whether content has comment form.
	 *
	 * @since 1.1.0
	 *
	 * @return bool
	 */
	public static function has_comment_form() {
		return is_singular() && comments_open();
	}

	/**
	 * Determines whether post thumbnail can be displayed.
	 *
	 * @since 1.2.0
	 *
	 * @param WP_Post|null $post_object Optional post. Global $post used if not provided.
	 * @return bool
	 */
	private static function can_show_post_thumbnail( $post_object ) {
		return ( self::is_wp_post( $post_object ) || is_null( $post_object ) ) &&
			! post_password_required( $post_object ) &&
			! is_attachment() &&
			has_post_thumbnail( $post_object );
	}
}
