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

use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Field\Query;
use SabaiApps\Directories\Component\Entity\Type\Query as EntityQuery;

class BooleanFilter extends AbstractFilter implements IConditionable {

	protected $_filterColumn = 'value', $_trueValue = true, $_nullOnly = false;

	protected function _fieldFilterInfo() {
		return array(
			'label'            => __( 'Single checkbox', 'directories-pro' ),
			'field_types'      => array( 'boolean', 'switch' ),
			'default_settings' => array(
				'checkbox_label' => null,
				'hide_empty'     => false,
				'hide_count'     => false,
				'inverse'        => false,
			),
			'facetable'        => true,
		);
	}

	public function fieldFilterSettingsForm( IField $field, array $settings, array $parents = array() ) {
		$form = array(
			'checkbox_label' => array(
				'#type'          => 'textfield',
				'#title'         => __( 'Checkbox label', 'directories-pro' ),
				'#description'   => __( 'Enter the label displayed next to the checkbox.', 'directories-pro' ),
				'#default_value' => $settings['checkbox_label'],
				'#required'      => true,
				'#weight'        => 1,
			),
			'hide_empty'     => array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Hide empty', 'directories-pro' ),
				'#default_value' => ! empty( $settings['hide_empty'] ),
				'#weight'        => 5,
			),
			'inverse'        => array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Inverse results', 'directories-pro' ),
				'#default_value' => ! empty( $settings['inverse'] ),
				'#weight'        => 7,
			),
		);

		if ( $this->_application->getComponent( 'View' )->getConfig( 'filters', 'facet_count' ) ) {
			$form['hide_count'] = array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Hide count', 'directories-pro' ),
				'#default_value' => $settings['hide_count'],
				'#weight'        => 6,
			);
		}
		return $form;
	}

	public function fieldFilterForm( IField $field, $filterName, array $settings, $request = null, ?EntityQuery $query = null, ?array $current = null, $autoSubmit = true, $enableFacetCount = false, array $parents = array() ) {
		if ( false === $facets = $this->_getFacets( $field, $settings, $query, $enableFacetCount ) ) {
			return;
		}

		if ( ! isset( $current ) ) {
			$current = array(
				'#type'                    => 'checkbox',
				'#on_value'                => 1,
				'#off_value'               => '',
				'#on_label'                => $this->_getCheckboxLabel( $field, $settings ),
				'#switch'                  => false,
				'#entity_filter_form_type' => 'checkboxes',
			);
		}

		if ( isset( $facets ) ) {
			$count                = empty( $facets ) ? 0 : ( is_array( $facets ) ? array_sum( $facets ) : (int) $facets );
			$current['#count']    = $count;
			$current['#disabled'] = $count === 0;
		}

		return $current;
	}

	protected function _getFacets( IField $field, array $settings, ?EntityQuery $query = null, $enableFacetCount = false ) {
		if ( ! $enableFacetCount
			|| ! empty( $settings['hide_count'] )
		) {
			return;
		}

		$options = array();
		if ( $property = $field->isPropertyField() ) {
			$options[ empty( $settings['inverse'] ) ? 'filters_not' : 'filters' ] = array( $property => 0 );
		} else {
			$options['column'] = $this->_filterColumn;
			if ( ! $this->_nullOnly
				&& isset( $this->_filterColumn )
			) {
				$options[ empty( $settings['inverse'] ) ? 'filters' : 'filters_not' ] = array( $this->_filterColumn => $this->_trueValue );
			}
		}

		$facets = $this->_application->Entity_Facets( $field, $query->getFieldQuery(), $options );

		if ( ! $facets ) {
			return empty( $settings['hide_empty'] ) ? array() : false;
		}

		return $facets;
	}

	protected function _getCheckboxLabel( IField $field, array $settings ) {
		return sprintf( $settings['checkbox_label'], $field->getFieldLabel( true ) );
	}

	public function fieldFilterIsFilterable( IField $field, array $settings, &$value, ?array $requests = null ) {
		return isset( $value[0] ) && is_numeric( $value[0] );
	}

	public function fieldFilterDoFilter( Query $query, IField $field, array $settings, $value, array &$sorts ) {
		$value = (bool) $value;
		if ( ! empty( $settings['inverse'] ) ) {
			$value = ! $value;
		}

		if ( ! $value ) {
			if ( $this->_nullOnly ) {
				if ( $field->isPropertyField() ) {
					$query->fieldIs( $field, 0 );
				} else {
					$query->fieldIsNull( $field, $this->_filterColumn );
				}
			} else {
				$query->startCriteriaGroup( 'OR' )
					->fieldIsNull( $field, $this->_filterColumn )
					->fieldIsNot( $field, $this->_trueValue, $this->_filterColumn )
					->finishCriteriaGroup();
			}
		} elseif ( $this->_nullOnly ) {
			if ( $field->isPropertyField() ) {
				$query->fieldIsNot( $field, 0 );
			} else {
				$query->fieldIsNotNull( $field, $this->_filterColumn );
			}
		} else {
			$query->fieldIs( $field, $this->_trueValue, $this->_filterColumn );
		}
	}

	public function fieldFilterLabels( IField $field, array $settings, $value, $form, $defaultLabel ) {
		return array( $value => $this->_application->H( $this->_getCheckboxLabel( $field, $settings ) ) );
	}

	public function fieldFilterConditionableInfo( IField $field ) {
		return array(
			'' => array(
				'compare' => array( 'empty', 'filled' ),
			),
		);
	}

	public function fieldFilterConditionableRule( IField $field, $filterName, array $settings, $compare, $value = null, $name = '' ) {
		switch ( $compare ) {
			case 'empty':
				return array(
					'type'  => 'checked',
					'value' => false,
				);
			case 'filled':
				return array(
					'type'  => 'unchecked',
					'value' => false,
				);
			default:
				return;
		}
	}
}
