<?php
namespace SabaiApps\Directories\Component\Notification\Event;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Form\Form;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Request;

abstract class AbstractEntityEvent extends AbstractEvent {

	protected $_bundleType, $_paramEntityStatus = null;

	public function __construct( Application $application, $name, $bundleType ) {
		parent::__construct( $application, $name );
		$this->_bundleType = $bundleType;
	}

	final protected function _notificationEventInfo() {
		$info = $this->_notificationEntityEventInfo();
		if ( strpos( $info['label'], '%' ) !== false ) {
			$info['label'] = sprintf( $info['label'], $this->_getContentTypeLabel() );
		}

		return $info;
	}

	abstract protected function _notificationEntityEventInfo();

	public function notificationEventSettingsForm( array $settings, array $parents = array() ) {
		$directories = array();
		foreach ( $this->_application->Entity_Bundles_byType( $this->_bundleType ) as $bundle ) {
			if ( ! $this->_isEventBundle( $bundle )
				|| ( ! $directory = $this->_application->getModel( 'Directory', 'Directory' )->fetchById( $bundle->group ) )
				|| ( ! $directory_type = $this->_application->Directory_Types_impl( $directory->type, true ) )
			) {
				continue;
			}

			$directories[ $bundle->group ] = $bundle->getGroupLabel();
		}

		if ( count( $directories ) === 1 ) {
			return array(
				'directories' => array(
					'#type'          => 'hidden',
					'#default_value' => 'single',
				),
				'single'      => array(
					'#type'          => 'hidden',
					'#default_value' => array_keys( $directories )[0],
				),
			);
		}

		return array(
			'directories' => array(
				'#type'          => 'select',
				'#options'       => array(
					''        => __( 'All Directories', 'directories-pro' ),
					'include' => __( 'Enable for selected directories', 'directories-pro' ),
					'exclude' => __( 'Disable for selected directories', 'directories-pro' ),
				),
				'#horizontal'    => true,
				'#title'         => __( 'Directories', 'directories-pro' ),
				'#default_value' => isset( $settings['directories'] ) ? $settings['directories'] : '',
				'#required'      => true,
			),
			'include'     => array(
				'#type'          => 'checkboxes',
				'#options'       => $directories,
				'#horizontal'    => true,
				'#default_value' => isset( $settings['include'] ) ? $settings['include'] : null,
				'#required'      => true,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s"]', $this->_application->Form_Form_fieldName( array( $parents, 'directories' ) ) ) => array( 'value' => 'include' ),
					),
				),
			),
			'exclude'     => array(
				'#type'          => 'checkboxes',
				'#options'       => $directories,
				'#horizontal'    => true,
				'#default_value' => isset( $settings['exclude'] ) ? $settings['exclude'] : null,
				'#required'      => true,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s"]', $this->_application->Form_Form_fieldName( array( $parents, 'directories' ) ) ) => array( 'value' => 'exclude' ),
					),
				),
			),
		);
	}

	protected function _isEventBundle( Bundle $bundle ) {
		return ! empty( $bundle->info['public'] );
	}

	public function notificationEventMessageMeta( array $settings ) {
		$meta = array(
			'recipients' => array(),
		);
		if ( $bundle = $this->_isSingleContentType( $settings ) ) {
			$meta['tags']        = $this->_application->Entity_Tokens( $bundle, true, array( 'site' => true ) );
			$email_field_options = $this->_application->Entity_Field_options(
				$bundle,
				array(
					'interface'   => 'Field\Type\IEmail',
					'name_prefix' => 'field_',
					'prefix'      => $bundle->getLabel( 'singular' ) . ' - ' . __( 'Field - ', 'directories-pro' ),
					'exclude'     => array( 'user_email' ),
				)
			);
			$phone_field_options = $this->_application->Entity_Field_options(
				$bundle,
				array(
					'type'        => 'phone',
					'name_prefix' => 'field_',
					'prefix'      => $bundle->getLabel( 'singular' ) . ' - ' . __( 'Field - ', 'directories-pro' ),
				)
			);
			switch ( $bundle->entitytype_name ) {
				case 'post':
					$meta['recipients']['author'] = $bundle->getLabel( 'singular' ) . ' - ' . __( 'Author', 'directories-pro' );
					if ( ! empty( $bundle->info['parent'] )
						&& ( $parent_bundle = $this->_application->Entity_Bundle( $bundle->info['parent'] ) )
					) {
						$parent_label                        = sprintf( __( 'Parent %s', 'directories-pro' ), $parent_bundle->getLabel( 'singular' ) );
						$meta['recipients']['parent_author'] = $parent_label . ' - ' . __( 'Author', 'directories-pro' );
						$email_field_options                += $this->_application->Entity_Field_options(
							$parent_bundle,
							array(
								'interface'   => 'Field\Type\IEmail',
								'name_prefix' => 'parent_field_',
								'prefix'      => $parent_label . ' - ' . __( 'Field - ', 'directories-pro' ),
								'exclude'     => array( 'user_email' ),
							)
						);
						$phone_field_options                += $this->_application->Entity_Field_options(
							$parent_bundle,
							array(
								'type'        => 'phone',
								'name_prefix' => 'parent_field_',
								'prefix'      => $parent_label . ' - ' . __( 'Field - ', 'directories-pro' ),
							)
						);
					}
					break;
				case 'user':
					$meta['recipients']['user'] = $bundle->getLabel( 'singular' );
					break;
			}
			foreach ( $email_field_options as $name => $label ) {
				$meta['recipients'][ $name ] = array(
					'type'  => 'email',
					'label' => $label,
				);
			}
			foreach ( $phone_field_options as $name => $label ) {
				$meta['recipients'][ $name ] = array(
					'type'  => 'phone',
					'label' => $label,
				);
			}
		} else {
			$meta['tags'] = $this->_application->Entity_Tokens( $this->_bundleType, false, array( 'site' => true ) );
			switch ( $this->_application->Entity_BundleTypeInfo( $this->_bundleType, 'entity_type' ) ) {
				case 'post':
					$meta['recipients']['author'] = $this->_getContentTypeLabel() . ' - ' . __( 'Author', 'directories-pro' );
					if ( $this->_application->Entity_BundleTypeInfo( $this->_bundleType, 'parent' ) ) {
						$meta['recipients']['parent_author'] = __( 'Parent post author', 'directories-pro' );
					}
					break;
				case 'user':
					$meta['recipients']['user'] = $this->_getContentTypeLabel();
					break;
			}
		}

		return $meta;
	}

	protected function _isSingleContentType( array $settings ) {
		if ( empty( $settings['directories'] ) ) {
			return false;
		}

		if ( $settings['directories'] === 'single' ) {
			$bundle_group = $settings['single'];
		} else {
			if ( $settings['directories'] !== 'include'
				|| count( $settings['include'] ) > 1
			) {
				return false;
			}

			$bundle_group = $settings['include'][0];
		}
		if ( ! $bundle = $this->_application->Entity_Bundle( $this->_bundleType, $bundle_group ) ) {
			throw new Exception\RuntimeException( 'Invalid directory: ' . $bundle_group );
		}
		return $bundle;
	}

	protected function _getContentTypeLabel( ?array $settings = null, $type = 'label_singular' ) {
		if ( isset( $settings )
			&& ( $bundle = $this->_isSingleContentType( $settings ) )
		) {
			return $bundle->info[ $type ];
		}

		return $this->_application->Entity_BundleTypeInfo( $this->_bundleType, $type );
	}

	protected function _isBundleEnabled( $bundle, array $settings ) {
		if ( ( ! $bundle = $this->_application->Entity_Bundle( $bundle ) )
			|| $bundle->type !== $this->_bundleType
		) {
			return false;
		}

		switch ( $settings['directories'] ) {
			case 'include':
				return in_array( $bundle->group, $settings['include'] );
			case 'exclude':
				return ! in_array( $bundle->group, $settings['exclude'] );
			default:
				return true;
		}
	}

	public function notificationEventParamSettingsForm( array $settings, array $parents = array() ) {
		return array(
			'entity' => array(
				'#title'                 => sprintf(
					__( 'Select %s', 'directories-pro' ),
					( $bundle = $this->_isSingleContentType( $settings ) ) ? $bundle->getLabel( 'singular' ) : $this->_application->Entity_BundleTypeInfo( $this->_bundleType, 'label_singular' )
				),
				'#type'                  => 'autocomplete',
				'#select2'               => true,
				'#select2_ajax'          => true,
				'#select2_ajax_url'      => $this->_getQueryEntitiesUrl( $settings, $this->_paramEntityStatus ),
				'#select2_item_text_key' => 'title',
				'#horizontal'            => true,
				'#element_validate'      => array(
					function ( Form $form, &$value, $element ) {
						if ( ! $entity = $this->_application->Entity_Entity( 'post', $value ) ) {
							$form->setError( 'Invalid entity.', $element );
							return;
						}
						if ( isset( $this->_paramEntityStatus )
						&& $entity->getStatus() !== ( $status_required = $this->_application->Entity_Status( 'post', $this->_paramEntityStatus ) )
								) {
								$form->setError( sprintf( 'You must select a post with "%s" status.', $status_required ), $element );
						}
					},
				),
			),
		);
	}

	protected function _getQueryEntitiesUrl( array $settings, $status = null, $num = 5 ) {
		return $this->_application->MainUrl(
			'/_drts/entity/' . $this->_bundleType . '/query',
			$this->_getQueryEntitiesParams( $settings, $status, $num ),
			'',
			'&'
		);
	}

	protected function _getQueryEntitiesParams( array $settings, $status = null, $num = 5 ) {
		$params = array(
			Request::PARAM_CONTENT_TYPE => 'json',
			'num'                       => $num,
		);
		if ( $bundle = $this->_isSingleContentType( $settings ) ) {
			$params['bundle'] = $bundle->name;
		}
		if ( isset( $status ) ) {
			$params['status'] = $status;
		}
		return $params;
	}
}
