<?php
namespace SabaiApps\Directories\Component\Field\Filter;

use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Entity;

abstract class AbstractOptionFilter extends AbstractFilter {

	protected $_label = null, $_fieldTypes = array(), $_defaultSettings = array(), $_emptyValue = '', $_valueColumn = 'value', $_prefixLabel = true, $_labelSortable = false;

	protected function _fieldFilterInfo() {
		return array(
			'label'            => $this->_label,
			'field_types'      => $this->_fieldTypes,
			'default_settings' => $this->_defaultSettings + array(
				'type'          => 'checkboxes',
				'columns'       => 1,
				'show_more'     => array( 'num' => 10 ),
				'andor'         => 'AND',
				'default_text'  => '',
				'no_fancy'      => true,
				'sort'          => false,
				'hide_empty'    => false,
				'hide_count'    => false,
				'sort_by_count' => false,
			),
			'facetable'        => true,
		);
	}

	public function fieldFilterSettingsForm( IField $field, array $settings, array $parents = array() ) {
		$form = array(
			'type'         => array(
				'#title'         => __( 'Form field type', 'directories-pro' ),
				'#type'          => 'select',
				'#options'       => array(
					'checkboxes' => __( 'Checkboxes', 'directories-pro' ),
					'radios'     => __( 'Radio buttons', 'directories-pro' ),
					'select'     => __( 'Select list', 'directories-pro' ),
				),
				'#default_value' => $settings['type'],
				'#weight'        => 5,
			),
			'columns'      => array(
				'#type'          => 'select',
				'#title'         => __( 'Number of columns', 'directories-pro' ),
				'#options'       => array(
					1 => 1,
					2 => 2,
					3 => 3,
					4 => 4,
				),
				'#default_value' => $settings['columns'],
				'#weight'        => 10,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s[type]"]', $states_selector_prefix = $this->_application->Form_Form_fieldName( $parents ) ) => array(
							'type'  => 'one',
							'value' => array( 'checkboxes', 'radios' ),
						),
					),
				),
			),
			'show_more'    => array(
				'#states' => array(
					'visible' => array(
						sprintf( '[name="%s[type]"]', $states_selector_prefix ) => array(
							'type'  => 'one',
							'value' => array( 'checkboxes', 'radios' ),
						),
						// sprintf('[name="%s[columns]"]', $states_selector_prefix) => ['value' => 1],
					),
				),
				'num'     => array(
					'#type'          => 'slider',
					'#integer'       => true,
					'#min_value'     => 0,
					'#max_value'     => 50,
					'#min_text'      => __( 'Show all', 'directories-pro' ),
					'#title'         => __( 'Number of options to display', 'directories-pro' ),
					'#description'   => __( 'If there are more options than the number specified, those options are hidden until "more" link is clicked.', 'directories-pro' ),
					'#default_value' => $settings['show_more']['num'],
				),
				'scroll'  => array(
					'#type'          => 'checkbox',
					'#title'         => __( 'Show scroll bar', 'directories-pro' ),
					'#weight'        => 31,
					'#default_value' => ! empty( $settings['show_more']['scroll'] ),
					'#states'        => array(
						'visible' => array(
							sprintf( '[name="%s[show_more][num]"]', $this->_application->Form_Form_fieldName( $parents ) ) => array( 'value' => 0 ),
							sprintf( '[name="%s[columns]"]', $this->_application->Form_Form_fieldName( $parents ) ) => array( 'value' => 1 ),
						),
					),
				),
				'#weight' => 15,
			),
			'andor'        => array(
				'#title'         => __( 'Match any or all', 'directories-pro' ),
				'#type'          => 'select',
				'#options'       => array(
					'OR'  => __( 'Match any', 'directories-pro' ),
					'AND' => __( 'Match all', 'directories-pro' ),
				),
				'#default_value' => $settings['andor'],
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s[type]"]', $states_selector_prefix ) => array( 'value' => 'checkboxes' ),
					),
				),
				'#weight'        => 20,
			),
			'default_text' => array(
				'#type'          => 'textfield',
				'#title'         => __( 'Default text', 'directories-pro' ),
				'#default_value' => $settings['default_text'],
				'#placeholder'   => _x( 'Any', 'option', 'directories-pro' ),
				'#weight'        => 25,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s[type]"]', $states_selector_prefix ) => array(
							'type'  => 'one',
							'value' => array( 'select', 'radios' ),
						),
					),
				),
			),
			'no_fancy'     => array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Disable fancy dropdown', 'directories-pro' ),
				'#default_value' => ! empty( $settings['no_fancy'] ),
				'#weight'        => 30,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s[type]"]', $states_selector_prefix ) => array( 'value' => 'select' ),
					),
				),
			),
		);
		if ( $this->_labelSortable ) {
			$form['sort'] = array(
				'#title'         => __( 'Sort by label', 'directories-pro' ),
				'#type'          => 'checkbox',
				'#default_value' => ! empty( $settings['sort'] ),
				'#weight'        => 32,
			);
		}
		if ( $this->_application->getComponent( 'View' )->getConfig( 'filters', 'facet_count' ) ) {
			$form += array(
				'hide_empty'    => array(
					'#type'          => 'checkbox',
					'#title'         => __( 'Hide empty', 'directories-pro' ),
					'#default_value' => ! empty( $settings['hide_empty'] ),
					'#weight'        => 34,
				),
				'hide_count'    => array(
					'#type'          => 'checkbox',
					'#title'         => __( 'Hide count', 'directories-pro' ),
					'#default_value' => $settings['hide_count'],
					'#weight'        => 35,
				),
				'sort_by_count' => array(
					'#type'          => 'checkbox',
					'#title'         => __( 'Sort options by count', 'directories-pro' ),
					'#default_value' => $settings['sort_by_count'],
					'#weight'        => 40,
					'#states'        => array(
						'invisible_or' => array(
							sprintf( '[name="%s[hide_count]"]', $states_selector_prefix ) => array(
								'type'  => 'checked',
								'value' => true,
							),
							sprintf( '[name="%s[sort]"]', $states_selector_prefix ) => array(
								'type'  => 'checked',
								'value' => true,
							),
						),
					),
				),
			);
		}

		return $form;
	}

	public function fieldFilterForm( IField $field, $filterName, array $settings, $request = null, ?Entity\Type\Query $query = null, ?array $current = null, $autoSubmit = true, $enableFacetCount = false, array $parents = array() ) {
		if ( $enableFacetCount
			&& ( empty( $settings['hide_count'] ) || ! empty( $settings['hide_empty'] ) )
		) {
			$field_query = $query->getFieldQuery();
			if ( $settings['type'] !== 'checkboxes' // always OR if not checkboxes
				|| $settings['andor'] === 'OR'
			) {
				// Clone field query and exclude queries for the current choice field and fetch facets
				$field_query = clone $field_query;
				$field_query->removeNamedCriteria( $field->getFieldName() );
			}
			$facets = $this->_application->Entity_Facets( $field, $field_query, $this->_getFacetOptions( $field, $settings ) );
		}

		if ( ! isset( $current ) ) {
			$option_no_escape = false;
			if ( ! $options = $this->_getOptions( $field, $settings, $option_no_escape ) ) {
				return; // no options
			}

			if ( $this->_labelSortable
				&& ! empty( $settings['sort'] )
			) {
				asort( $options );
			}

			switch ( $settings['type'] ) {
				case 'radios':
					$options[ $this->_emptyValue ] = $this->_getDefaultText( $field, $settings );
					$default_value                 = $this->_emptyValue;
					break;
				case 'select':
					$options                       = array_map( 'strip_tags', $options );
					$options[ $this->_emptyValue ] = $this->_getDefaultText( $field, $settings );
					$default_value                 = $this->_emptyValue;
					break;
				case 'checkboxes':
				default:
					$default_value    = null;
					$settings['type'] = 'checkboxes';
			}

			$current = array(
				'#type'                    => $settings['type'],
				'#select2'                 => empty( $settings['no_fancy'] ),
				'#placeholder'             => $this->_getDefaultText( $field, $settings ),
				'#options'                 => $options,
				'#options_valid'           => array_keys( $options ),
				'#options_visible_count'   => $settings['show_more']['num'],
				'#options_scroll'          => ! empty( $settings['show_more']['scroll'] ),
				'#option_no_escape'        => ! empty( $option_no_escape ),
				'#default_value'           => $default_value,
				'#entity_filter_form_type' => $settings['type'],
				'#options_disabled'        => array(),
				'#columns'                 => ! $this->_application->isRunning() || empty( $settings['columns'] ) ? 1 : $settings['columns'],
				'#disable_select_all'      => true,
			);
		}

		if ( isset( $facets ) ) {
			$_request = isset( $request ) ? (array) $request : array();
			foreach ( array_keys( $current['#options'] ) as $value ) {
				if ( empty( $facets[ $value ] ) ) {
					if ( $value !== $this->_emptyValue ) {
						if ( ! empty( $settings['hide_empty'] ) ) {
							unset( $current['#options'][ $value ] );
						} else {
							if ( ! in_array( $value, $_request ) ) {
								// Disable only when the option is currently not selected
								$current['#options_disabled'][ $value ] = $value;
							}
							$current['#options'][ $value ] = array(
								'#title' => $current['#options'][ $value ],
								'#count' => 0,
							);
						}
					}
				} elseif ( empty( $settings['hide_count'] ) ) {
						$current['#options'][ $value ] = array(
							'#title' => $current['#options'][ $value ],
							'#count' => $facets[ $value ],
						);
				}
			}
			if ( empty( $settings['hide_count'] )
				&& ! empty( $settings['sort_by_count'] )
			) {
				uasort(
					$current['#options'],
					function ( $a, $b ) {
						return isset( $a['#count'] ) && isset( $b['#count'] ) && $a['#count'] > $b['#count'] ? -1 : 1;
					}
				);
			}
		}

		return empty( $current['#options'] ) ? null : $current;
	}

	protected function _getDefaultText( IField $field, array $settings ) {
		if ( isset( $settings['default_text'] )
			&& strlen( (string) $settings['default_text'] )
		) {
			return $this->_application->System_TranslateString( $settings['default_text'], $field->getFieldName() . '_option_default_text', 'view_filter' );
		}
		return _x( 'Any', 'option', 'directories-pro' );
	}

	protected function _getFacetOptions( IField $field, array $settings ) {
		return array(
			'column' => $this->_getValueColumn( $field, $settings ),
		);
	}

	protected function _getValueColumn( IField $field, array $settings ) {
		return $this->_valueColumn;
	}

	abstract protected function _getOptions( IField $field, array $settings, &$noEscape = false );

	public function fieldFilterIsFilterable( IField $field, array $settings, &$value, ?array $requests = null ) {
		return $settings['type'] === 'checkboxes' ? ! empty( $value ) : $value != $this->_emptyValue;
	}

	public function fieldFilterLabels( IField $field, array $settings, $value, $form, $defaultLabel ) {
		$ret    = array();
		$prefix = $this->_prefixLabel ? $this->_application->H( $defaultLabel ) . ': ' : '';
		if ( empty( $form['#option_no_escape'] ) ) {
			foreach ( (array) $value as $_value ) {
				$ret[ $_value ] = $prefix . $this->_application->H( $form['#options'][ $_value ] );
			}
		} else {
			foreach ( (array) $value as $_value ) {
				$ret[ $_value ] = $prefix . $form['#options'][ $_value ];
			}
		}

		return $ret;
	}
}
