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

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Field\Type\IHumanReadable;
use SabaiApps\Directories\Exception\InvalidArgumentException;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Entity\Type\IEntity;

class TokensHelper {

	protected static $_autoIncrementNum = 0;

	/**
	 * @param Application        $application
	 * @param Bundle|string|null $bundle
	 * @param bool               $includeFields
	 * @param array              $options
	 * @return array
	 */
	public function help( Application $application, $bundle = null, $includeFields = false, array $options = array() ) {
		$options += array(
			'tag'            => '%',
			'prefix'         => '',
			'fields_options' => array(),
			'site'           => false,
			'current_user'   => false,
			'auto_increment' => false,
		);
		$tag      = $this->_getTag( $options['tag'] );
		$tokens   = array(
			$options['prefix'] . 'id',
			$options['prefix'] . 'title',
			$options['prefix'] . 'slug',
			$options['prefix'] . 'content_type',
			$options['prefix'] . 'author_id',
			$options['prefix'] . 'author_name',
			$options['prefix'] . 'author_email',
			$options['prefix'] . 'author_slug',
			$options['prefix'] . 'timestamp',
			$options['prefix'] . 'content',
			$options['prefix'] . 'permalink_url',
			$options['prefix'] . 'admin_permalink_url',
			$options['prefix'] . 'date_published',
			$options['prefix'] . 'date_modified',
		);
		if ( isset( $bundle ) ) {
			if ( $application->Entity_BundleTypeInfo( $bundle, 'parent' )
				|| $application->Entity_BundleTypeInfo( $bundle, 'parent_field' )
			) {
				$tokens[] = $options['prefix'] . 'parent_title';
				$tokens[] = $options['prefix'] . 'parent_permalink_url';
				$tokens[] = $options['prefix'] . 'parent_author_name';
				$tokens[] = $options['prefix'] . 'parent_author_email';
				$tokens[] = $options['prefix'] . 'parent_author_slug';
			}
			if ( $includeFields
				&& $bundle instanceof Bundle
			) {
				$fields = $application->Entity_Field_options(
					$bundle->name,
					array(
						'interface'        => 'Field\Type\IHumanReadable',
						'return_disabled'  => false,
						'exclude_property' => true,
						'name_prefix'      => $options['prefix'] . 'field_',
					) + $options['fields_options']
				);
				foreach ( array_keys( $fields ) as $field_name ) {
					$tokens[] = $field_name;
				}
			}
		}
		if ( $options['current_user'] ) {
			$tokens[] = 'current_user_id';
			$tokens[] = 'current_user_name';
			$tokens[] = 'current_user_display_name';
		}
		if ( $options['site'] ) {
			$tokens[] = 'site_url';
			$tokens[] = 'site_name';
			$tokens[] = 'site_email';
		}
		if ( $options['auto_increment'] ) {
			$tokens[] = 'auto_increment_number';
		}
		array_walk(
			$tokens,
			function ( &$token ) use ( $tag ) {
				$token = $tag . $token . $tag;
			}
		);

		return $application->Filter( 'entity_tokens', $tokens, array( $bundle, $tag ) );
	}

	protected function _getTag( $tag = '%' ) {
		if ( ! strlen( $tag ) ) {
			$tag = '%';
		} elseif ( strpos( $tag, '#' ) ) {
			throw new InvalidArgumentException( 'Tag may not contain "#".' );
		}
		return $tag;
	}

	public function replace( Application $application, $text, ?IEntity $entity = null, $includeFields = false, array $options = array() ) {
		$options += array(
			'escape'         => true,
			'encode'         => false,
			'tag'            => '%',
			'prefix'         => '',
			'site'           => false,
			'current_user'   => false,
			'auto_increment' => false,
		);
		$tag      = $this->_getTag( $options['tag'] );
		if ( strpos( $text, $tag ) === false
			|| ! preg_match_all( '#' . $tag . '(.+?)' . $tag . '#', $text, $matches )
		) {
			return $text;
		}

		$replacements = array();
		foreach ( $matches[1] as $i => $key ) {
			switch ( $key ) {
				case $options['prefix'] . 'id':
					$value = $entity ? $entity->getId() : '';
					break;
				case $options['prefix'] . 'title':
					$value = $entity ? $application->Entity_Title( $entity ) : '';
					break;
				case $options['prefix'] . 'slug':
					$value = $entity ? $entity->getSlug() : '';
					break;
				case $options['prefix'] . 'author_id':
					$value = $entity ? $entity->getAuthorId() : '';
					break;
				case $options['prefix'] . 'author_name':
					$value = $entity ? ( ( $author = $application->Entity_Author( $entity ) ) ? $author->name : __( 'Guest', 'drts' ) ) : '';
					break;
				case $options['prefix'] . 'author_email':
					$value = $entity ? ( ( $author = $application->Entity_Author( $entity ) ) ? $author->email : '' ) : '';
					break;
				case $options['prefix'] . 'author_slug':
					$value = $entity ? ( ( $author = $application->Entity_Author( $entity ) ) ? $author->slug : '' ) : '';
					break;
				case $options['prefix'] . 'timestamp':
					$value = $entity ? $entity->getTimestamp() : '';
					break;
				case $options['prefix'] . 'content':
					$value = $entity ? ( ( '' !== $content = $entity->getContent() ) ? $application->System_Text_summarize( $content, 300 ) : '' ) : '';
					break;
				case $options['prefix'] . 'permalink_url':
					$value = $entity ? rtrim( $application->Entity_PermalinkUrl( $entity ), '/' ) . '/' : '';
					break;
				case $options['prefix'] . 'date_published':
					$value = $entity ? $application->System_Date( $entity->getTimestamp() ) : '';
					break;
				case $options['prefix'] . 'date_modified':
					$value = $entity ? $application->System_Date( $entity->getModified() ) : '';
					break;
				case $options['prefix'] . 'parent_title':
					$value = $entity ? ( ( $parent_entity = $application->Entity_ParentEntity( $entity ) ) ? $parent_entity->getTitle() : '' ) : '';
					break;
				case $options['prefix'] . 'parent_permalink_url':
					$value = $entity ? ( ( $parent_entity = $application->Entity_ParentEntity( $entity ) ) ? rtrim( $application->Entity_PermalinkUrl( $parent_entity ), '/' ) . '/' : '' ) : '';
					break;
				case $options['prefix'] . 'parent_author_name':
					$value = $entity ? ( ( $parent_entity = $application->Entity_ParentEntity( $entity ) ) && ( $author = $application->Entity_Author( $parent_entity ) ) ? $author->name : __( 'Guest', 'drts' ) ) : '';
					break;
				case $options['prefix'] . 'parent_author_email':
					$value = $entity ? ( ( $parent_entity = $application->Entity_ParentEntity( $entity ) ) && ( $author = $application->Entity_Author( $parent_entity ) ) ? $author->email : '' ) : '';
					break;
				case $options['prefix'] . 'parent_author_slug':
					$value = $entity ? ( ( $parent_entity = $application->Entity_ParentEntity( $entity ) ) && ( $author = $application->Entity_Author( $parent_entity ) ) ? $author->slug : '' ) : '';
					break;
				case $options['prefix'] . 'admin_permalink_url':
					$value = $entity ? rtrim( $application->Entity_AdminUrl( $entity, '&' ), '/' ) . '/' : '';
					break;
				case $options['prefix'] . 'content_type':
					if ( ! $entity ) {
						$value = '';
					} else {
						$bundle = $application->Entity_Bundle( $entity );
						$value  = $bundle->getGroupLabel() . ' - ' . $bundle->getLabel( 'singular' );
					}
					break;
				case 'current_user_id':
					$value = $application->getUser()->id;
					break;
				case 'current_user_name':
					$value = $application->getUser()->username;
					break;
				case 'current_user_display_name':
					$value = $application->getUser()->name;
					break;
				case 'site_url':
					$value = $application->getPlatform()->getSiteUrl();
					break;
				case 'site_name':
					$value = $application->getPlatform()->getSiteName();
					break;
				case 'site_email':
					$value = $application->getPlatform()->getSiteEmail();
					break;
				case 'auto_increment_number':
					$value = ++self::$_autoIncrementNum;
					break;
				default:
					continue 2;
			}
			unset( $matches[1][ $i ] );
			$replacements[ $tag . $key . $tag ] = $value;
		}
		if ( $includeFields
			&& ! empty( $matches[1] )
			&& preg_match_all( '#' . $tag . $options['prefix'] . 'field_(.+?)' . $tag . '#', $text, $field_matches )
		) {
			foreach ( $field_matches[1] as $field_name ) {
				$match = $field_name;
				$key   = null;
				if ( $pos = strpos( $field_name, '__' ) ) {
					$key        = substr( $field_name, $pos + 2 );
					$field_name = substr( $field_name, 0, $pos );
				}
				$token = $tag . 'field_' . $match . $tag;
				if ( ( $field = $application->Entity_Field( $entity, $field_name ) )
					&& ( $field_type = $application->Field_Type( $field->getFieldType(), true ) )
					&& $field_type instanceof IHumanReadable
				) {
					$replacements[ $token ] = $field_type->fieldHumanReadableText( $field, $entity, null, $key );
					if ( $options['escape'] ) {
						$replacements[ $token ] = $application->H( $replacements[ $token ] );
					} elseif ( $options['encode'] ) {
						$replacements[ $token ] = rawurlencode( $replacements[ $token ] );
					}
				} else {
					$replacements[ $token ] = '';
				}
			}
		}

		return strtr( $text, $application->Filter( 'entity_tokens_replace', $replacements, array( $entity, $tag ) ) );
	}
}
