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

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Form;
use SabaiApps\Directories\Component\Display\Controller\Admin\AddDisplay;
use SabaiApps\Directories\Component\View\Mode\IMode;
use SabaiApps\Directories\Component\View\Model\View;

class SettingsFormHelper {

	public function help( Application $application, Bundle $bundle, $view, ?array $submitValues = null ) {
		if ( $view instanceof View ) {
			$label           = $view->getLabel();
			$name            = $view->name;
			$mode            = $view->mode;
			$settings        = $view->data['settings'];
			$is_default_view = $view->isDefault();
		} else {
			$label           = $name = null;
			$mode            = isset( $view['mode'] ) ? $view['mode'] : null;
			$settings        = isset( $view['settings'] ) ? $view['settings'] : array();
			$is_default_view = ! empty( $view['is_default'] );
		}

		$form = array(
			'#tabs'      => array(
				'general' => array(
					'#title'  => _x( 'General', 'settings tab', 'directories-pro' ),
					'#weight' => 1,
				),
			),
			'#tab_style' => 'pill',
			'general'    => array(
				'#tree'         => true,
				'#tab'          => 'general',
				'label'         => array(
					'#type'          => 'textfield',
					'#title'         => __( 'View label', 'directories-pro' ),
					'#description'   => __( 'Enter a label used for administration purpose only.', 'directories-pro' ),
					'#max_length'    => 255,
					'#required'      => true,
					'#horizontal'    => true,
					'#default_value' => $label,
				),
				'name'          => array(
					'#type'             => 'textfield',
					'#title'            => __( 'View name', 'directories-pro' ),
					'#description'      => __( 'Enter a unique name so that that it can be easily referenced. Only lowercase alphanumeric characters and underscores are allowed.', 'directories-pro' ),
					'#max_length'       => 50,
					'#required'         => true,
					'#regex'            => '/^[a-z0-9_]+$/',
					'#horizontal'       => true,
					'#slugify'          => isset( $name ),
					'#states'           => isset( $name ) ? null : array(
						'slugify' => array(
							'input[name="general[label]"]' => array(
								'type'  => 'filled',
								'value' => true,
							),
						),
					),
					'#element_validate' => array(
						function ( Form\Form $form, &$value, $element ) use ( $application, $bundle, $view ) {
							$query = $application->getModel( 'View', 'View' )->bundleName_is( $bundle->name )->name_is( $value );
							if ( $view instanceof View ) {
								$query->id_isNot( $view->id );
							}
							if ( $query->count() ) {
								$form->setError( __( 'The name is already taken.', 'directories-pro' ), $element );
							}
						},
					),
					'#default_value'    => $name,
				),
				'mode'          => array(
					'#title'         => __( 'View mode', 'directories-pro' ),
					'#type'          => 'select',
					'#horizontal'    => true,
					'#options'       => array(),
					'#default_value' => $mode,
				),
				'mode_settings' => array(
					'#tree' => true,
				),
			),
		);

		$features_disabled_by_mode = array();
		foreach ( array_keys( $application->View_Modes() ) as $view_mode_name ) {
			if ( ! $view_mode = $application->View_Modes_impl( $view_mode_name, $bundle, true ) ) {
				continue;
			}

			$form['general']['mode']['#options'][ $view_mode_name ]         = $view_mode->viewModeInfo( 'label' );
			$form['general']['mode_settings'][ $view_mode_name ]            = $this->mode(
				$application,
				$bundle,
				$view_mode,
				$mode === $view_mode_name ? $settings : array(),
				array( 'general', 'mode_settings', $view_mode_name ),
				$submitValues
			);
			$form['general']['mode_settings'][ $view_mode_name ]['#states'] = array(
				'visible' => array(
					'select[name="general[mode]"]' => array( 'value' => $view_mode_name ),
				),
			);
			$features_disabled_by_mode[ $view_mode_name ]                   = (array) $view_mode->viewModeInfo( 'features_disabled' );
		}

		$states = array();
		foreach ( $features_disabled_by_mode as $view_mode => $view_features ) {
			foreach ( $view_features as $key => $feature_name ) {
				if ( ! is_array( $feature_name ) ) {
					$states[ $feature_name ][] = $view_mode;
				} else {
					foreach ( $feature_name as $sub_feature_name ) {
						$states[ $key ][ $sub_feature_name ][] = $view_mode;
					}
				}
			}
		}

		$form['#validate'][] = function ( $form ) use ( $features_disabled_by_mode ) {
			$mode_selected = $form->values['general']['mode'];
			if ( ! empty( $features_disabled_by_mode[ $mode_selected ] ) ) {
				foreach ( $features_disabled_by_mode[ $mode_selected ] as $key => $feature_disabled ) {
					if ( is_int( $key ) ) {
						unset( $form->values[ $feature_disabled ] );
					} else {
						foreach ( $feature_disabled as $sub_feature_disabled ) {
							unset( $form->values[ $key ][ $sub_feature_disabled ] );
						}
					}
				}
			}
		};
		$features            = array(
			'sort'       => array(
				'label'  => __( 'Sort Settings', 'directories-pro' ),
				'weight' => 5,
			),
			'pagination' => array(
				'label'  => _x( 'Pagination', 'tab', 'directories-pro' ),
				'weight' => 10,
			),
			'filter'     => array(
				'label'  => __( 'Filter Settings', 'directories-pro' ),
				'weight' => 20,
			),
			'other'      => array(
				'label'  => __( 'Other', 'directories-pro' ),
				'weight' => 25,
			),
			'query'      => array(
				'label'  => __( 'Query Settings', 'directories-pro' ),
				'weight' => 15,
			),
		);
		foreach ( $features as $feature_name => $feature ) {
			if ( ! $feature_settings_form = $this->feature(
				$application,
				$bundle,
				$feature_name,
				isset( $settings[ $feature_name ] ) ? $settings[ $feature_name ] : array(),
				$is_default_view,
				'',
				array( $feature_name ),
				isset( $submitValues[ $feature_name ] ) ? $submitValues[ $feature_name ] : null
			) ) {
				continue;
			}

			$form[ $feature_name ] = array(
				'#tree' => true,
				'#tabs' => array(
					$feature_name => array(
						'#title'  => $feature['label'],
						'#weight' => $feature['weight'],
					),
				),
				'#tab'  => $feature_name,
			) + $feature_settings_form;
			if ( ! empty( $states[ $feature_name ] ) ) {
				if ( isset( $states[ $feature_name ][0] ) ) {
					$form[ $feature_name ]['#states']['invisible']['[name="general[mode]"]']
								= $form[ $feature_name ]['#tabs'][ $feature_name ]['#states']['invisible']['[name="general[mode]"]']
						= array(
							'type'  => 'one',
							'value' => $states[ $feature_name ],
						);
				}
				foreach ( array_keys( $states[ $feature_name ] ) as $sub_feature_name ) {
					if ( is_int( $sub_feature_name ) ) {
						$form[ $feature_name ]['#states']['invisible']['[name="general[mode]"]']['value'][]
									= $form[ $feature_name ]['#tabs'][ $feature_name ]['#states']['invisible']['[name="general[mode]"]']['value'][]
							= $states[ $feature_name ][ $sub_feature_name ];
					} else {
						$form[ $feature_name ][ $sub_feature_name ]['#states']['invisible']['[name="general[mode]"]']
							= array(
								'type'  => 'one',
								'value' => $states[ $feature_name ][ $sub_feature_name ],
							);
					}
				}
			}
		}

		return $application->Filter( 'view_feature_settings_form', $form, array( $bundle, $settings, $submitValues ) );
	}

	public function mode( Application $application, Bundle $bundle, $viewMode, array $settings, array $parents, ?array $submitValues = null ) {
		if ( ! $viewMode instanceof IMode ) {
			$viewMode = $application->View_Modes_impl( $viewMode, $bundle );
		}
		return $application->View_Modes_settingsForm( $viewMode, $bundle, $settings, $parents, $submitValues );
	}

	public function feature( Application $application, Bundle $bundle, $feature, array $settings, $isDefaultView = false, $prefix = '', array $parents = array(), ?array $submitValues = null ) {
		switch ( $feature ) {
			case 'sort':
				$sort_options_html = $application->Entity_Sorts_options( $bundle, true );
				$sort_options      = array_map( 'strip_tags', $sort_options_html );
				$form              = array(
					'#element_validate' => array(
						function ( Form\Form $form, &$value, $element ) {
							if ( ! empty( $value['default'] ) ) {
								if ( empty( $value['options'] ) ) {
									$value['options'] = array();
								}
								if ( ! in_array( $value['default'], $value['options'] ) ) {
									$value['options'][] = $value['default'];
								}
							}
						},
					),
					'default'           => array(
						'#type'               => 'select',
						'#default_value'      => isset( $settings['default'] ) ? $settings['default'] : null,
						'#title'              => $prefix . __( 'Default sort order', 'directories-pro' ),
						'#options'            => $sort_options,
						'#required'           => true,
						'#display_unrequired' => true,
						'#horizontal'         => true,
						'#weight'             => 5,
					),
					'secondary'         => array(
						'#type'          => 'select',
						'#default_value' => isset( $settings['secondary'] ) ? $settings['secondary'] : null,
						'#title'         => $prefix . __( 'Secondary sort order', 'directories-pro' ),
						'#options'       => array( '' => __( '— Select —', 'directories-pro' ) ) + $sort_options,
						'#required'      => false,
						'#horizontal'    => true,
						'#weight'        => 6,
					),
					'options'           => array(
						'#type'             => 'sortablecheckboxes',
						'#options'          => $sort_options_html,
						'#option_no_escape' => true,
						'#default_value'    => isset( $settings['options'] ) ? $settings['options'] : array( current( array_keys( $sort_options_html ) ) ),
						'#title'            => $prefix . __( 'Sort options', 'directories-pro' ),
						'#horizontal'       => true,
						'#weight'           => 1,
					),
				);
				if ( $application->Entity_BundleTypeInfo( $bundle, 'featurable' ) ) {
					$form['stick_featured'] = array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show featured items first', 'directories-pro' ),
						'#default_value' => ! empty( $settings['stick_featured'] ),
						'#horizontal'    => true,
						'#weight'        => 10,
					);
					if ( $isDefaultView ) {
						$form['stick_featured_term_only'] = array(
							'#type'          => 'checkbox',
							// '#switch' => false,
							'#title'         => $prefix . __( 'Show featured items first on single term pages only', 'directories-pro' ),
							'#default_value' => ! empty( $settings['stick_featured_term_only'] ),
							'#horizontal'    => true,
							'#weight'        => 11,
							'#states'        => array(
								'visible' => array(
									sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'stick_featured' ) ) ) ) => array(
										'type'  => 'checked',
										'value' => true,
									),
								),
							),
						);
					}
				}
				return $form;

			case 'pagination':
				$no_pagination_selector = sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'no_pagination' ) ) ) );
				$type_selector          = sprintf( 'select[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'type' ) ) ) );
				return array(
					'#element_validate' => array(
						function ( Form\Form $form, &$value, $element ) {
							if ( ! isset( $form->values['general']['mode'] )
								|| ! in_array( $form->values['general']['mode'], array( 'list', 'masonry' ) )
							) {
								$value['type'] = '';
							}
						},
					),
					'no_pagination'     => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Disable pagination', 'directories-pro' ),
						'#default_value' => ! empty( $settings['no_pagination'] ),
						'#horizontal'    => true,
						'#weight'        => 1,
					),
					'type'              => array(
						'#type'          => 'select',
						'#title'         => $prefix . __( 'Pagination type', 'directories-pro' ),
						'#options'       => array(
							''          => __( 'Default', 'directories-pro' ),
							'load_more' => __( 'Load more button', 'directories-pro' ),
						),
						'#default_value' => isset( $settings['type'] ) ? $settings['type'] : '',
						'#states'        => array(
							'visible' => array(
								$no_pagination_selector  => array(
									'type'  => 'checked',
									'value' => false,
								),
								'[name="general[mode]"]' => array(
									'type'  => 'one',
									'value' => array( 'list', 'masonry' ),
								),
							),
						),
						'#horizontal'    => true,
						'#weight'        => 3,
					),
					'perpage'           => array(
						'#type'               => 'slider',
						'#title'              => $prefix . __( 'Items per page', 'directories-pro' ),
						'#default_value'      => isset( $settings['perpage'] ) ? $settings['perpage'] : 20,
						'#integer'            => true,
						'#required'           => true,
						'#display_unrequired' => true,
						'#max_value'          => $application->Filter( 'view_feature_settings_pagination_perpage_max', 200, array( $bundle, $isDefaultView ) ),
						'#min_value'          => 1,
						'#horizontal'         => true,
						'#states'             => array(
							'visible' => array(
								$no_pagination_selector => array(
									'type'  => 'checked',
									'value' => false,
								),
							),
						),
						'#weight'             => 5,
					),
					'allow_perpage'     => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Allow selection of number of items per page', 'directories-pro' ),
						'#default_value' => ! empty( $settings['allow_perpage'] ),
						'#horizontal'    => true,
						'#states'        => array(
							'visible' => array(
								$no_pagination_selector => array(
									'type'  => 'checked',
									'value' => false,
								),
								$type_selector          => array( 'value' => '' ),
							),
						),
						'#weight'        => 10,
					),
					'perpages'          => array(
						'#type'          => 'checkboxes',
						'#integer'       => true,
						'#title'         => $prefix . __( 'Allowed number of items per page', 'directories-pro' ),
						'#default_value' => isset( $settings['perpages'] ) ? $settings['perpages'] : array( 10, 20, 50 ),
						'#options'       => array_combine( $perpages = $application->Filter( 'view_pagination_perpages', array( 10, 12, 15, 20, 24, 30, 36, 48, 50, 60, 100, 120, 200 ) ), $perpages ),
						'#horizontal'    => true,
						'#states'        => array(
							'visible' => array(
								$no_pagination_selector => array(
									'type'  => 'checked',
									'value' => false,
								),
								$type_selector          => array( 'value' => '' ),
								sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'allow_perpage' ) ) ) ) => array(
									'type'  => 'checked',
									'value' => true,
								),
							),
						),
						'#weight'        => 15,
						'#columns'       => 6,
					),
					'load_more_label'   => array(
						'#type'          => 'textfield',
						'#title'         => $prefix . __( 'Custom "Load More" button label', 'directories-pro' ),
						'#states'        => array(
							'visible' => array(
								$no_pagination_selector  => array(
									'type'  => 'checked',
									'value' => false,
								),
								'[name="general[mode]"]' => array(
									'type'  => 'one',
									'value' => array( 'list', 'masonry' ),
								),
								$type_selector           => array( 'value' => 'load_more' ),
							),
						),
						'#horizontal'    => true,
						'#weight'        => 5,
						'#placeholder'   => __( 'Load More', 'directories-pro' ),
						'#default_value' => isset( $settings['load_more_label'] ) ? $settings['load_more_label'] : '',
					),
				);

			case 'filter':
				if ( ! $application->getComponent( 'View' )->isFilterable( $bundle ) ) {
					return array();
				}

				$show_filters_selector  = sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'show' ) ) ) );
				$show_in_modal_selector = sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'show_modal' ) ) ) );
				$form                   = array(
					'#element_validate' => array(
						function ( Form\Form $form, &$value, $element ) {
							if ( ! empty( $value['show_modal'] ) ) {
								$value['shown'] = false;
							}
						},
					),
					'show'              => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show filter form', 'directories-pro' ),
						'#default_value' => ! empty( $settings['show'] ),
						'#horizontal'    => true,
						'#weight'        => 5,
					),
					'shown'             => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Disable collapsing filter form', 'directories-pro' ),
						'#default_value' => ! empty( $settings['shown'] ),
						'#horizontal'    => true,
						'#weight'        => 11,
						'#states'        => array(
							'visible' => array(
								$show_filters_selector  => array(
									'type'  => 'checked',
									'value' => true,
								),
								$show_in_modal_selector => array(
									'type'  => 'checked',
									'value' => false,
								),
							),
						),
					),

					'hide_btn'          => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Hide filter button', 'directories-pro' ),
						'#default_value' => ! empty( $settings['hide_btn'] ),
						'#horizontal'    => true,
						'#weight'        => 11,
						'#states'        => array(
							'visible' => array(
								$show_filters_selector  => array(
									'type'  => 'checked',
									'value' => true,
								),
								$show_in_modal_selector => array(
									'type'  => 'checked',
									'value' => false,
								),
								sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'shown' ) ) ) ) => array(
									'type'  => 'checked',
									'value' => true,
								),
							),
						),
					),
				);

				if ( $isDefaultView ) {
					$form['show_mobile_only'] = array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show filter form on mobile only', 'directories-pro' ),
						'#default_value' => ! empty( $settings['show_mobile_only'] ),
						'#horizontal'    => true,
						'#weight'        => 7,
						'#states'        => array(
							'visible' => array(
								$show_filters_selector => array(
									'type'  => 'checked',
									'value' => true,
								),
							),
						),
					);
				}

				$displays = AddDisplay::existingDisplays( $application, $bundle->name, 'default', 'filters' );
				if ( count( $displays ) > 1 ) {
					$form['display'] = array(
						'#type'          => 'select',
						'#title'         => $prefix . __( 'Select filter group', 'directories-pro' ),
						'#options'       => $displays,
						'#horizontal'    => true,
						'#default_value' => isset( $settings['display'] ) && isset( $displays[ $settings['display'] ] ) ? $settings['display'] : null,
						'#weight'        => 7,
					);
				} else {
					$form['display'] = array(
						'#type'          => 'hidden',
						'#default_value' => 'default',
					);
				}

				if ( empty( $bundle->info['parent'] ) ) {
					$form['show_modal'] = array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show filter form in modal window', 'directories-pro' ),
						'#default_value' => ! empty( $settings['show_modal'] ),
						'#horizontal'    => true,
						'#weight'        => 10,
						'#states'        => array(
							'visible' => array(
								$show_filters_selector => array(
									'type'  => 'checked',
									'value' => true,
								),
							),
						),
					);
				}

				return $form;

			case 'query':
				$fields = $application->Entity_Field( $bundle );
				$form   = array(
					'#element_validate' => array(
						function ( Form\Form $form, &$value, $element ) {
							if ( empty( $value['fields'] ) ) {
								return;
							}

							$queries = array();
							foreach ( array_filter( $value['fields'] ) as $query ) {
								if ( ! strlen( $query['field'] )
									|| ! strlen( trim( $query['query'] ) )
								) {
									continue;
								}

								$queries[ $query['field'] ] = $query['query'];
							}
							$value['fields'] = $queries;
						},
					),
					'fields'            => array(
						'#title'      => $prefix . __( 'Query by field', 'directories-pro' ),
						'#horizontal' => true,
						'#weight'     => 5,
					),
					'limit'             => array(
						'#type'          => 'number',
						'#title'         => $prefix . __( 'Max number of items to query', 'directories-pro' ),
						'#description'   => __( 'Enter 0 for no limit.', 'directories-pro' ),
						'#default_value' => empty( $settings['limit'] ) ? 0 : (int) $settings['limit'],
						'#horizontal'    => true,
						'#integer'       => true,
						'#weight'        => 10,
						'#min_value'     => 0,
					),
				);
				if ( isset( $submitValues['fields'] ) ) {
					// coming from form submission
					// need to check request values since fields may have been added/removed
					$queries = empty( $submitValues['fields'] ) ? array( null ) : $submitValues['fields'];
				} else {
					$queries = array();
					if ( ! empty( $settings['fields'] ) ) {
						foreach ( $settings['fields'] as $field_name => $query_str ) {
							$queries[] = array(
								'field' => $field_name,
								'query' => $query_str,
							);
						}
					}
					$queries[] = null;
				}
				foreach ( $queries as $i => $query ) {
					$form['fields'][ $i ] = array(
						'#type'          => 'field_query',
						'#fields'        => $fields,
						'#default_value' => $query,
					);
				}
				$form['fields']['_add'] = array(
					'#type'       => 'addmore',
					'#next_index' => ++$i,
				);

				return $form;

			case 'other':
				$form = array(
					'num'       => array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show number of items found', 'directories-pro' ),
						'#default_value' => ! empty( $settings['num'] ),
						'#horizontal'    => true,
						'#weight'        => 5,
					),
					'not_found' => array(
						'#weight' => 20,
						'custom'  => array(
							'#type'          => 'checkbox',
							'#title'         => $prefix . __( 'Customize "Not found" text', 'directories-pro' ),
							'#default_value' => ! empty( $settings['not_found']['custom'] ),
							'#horizontal'    => true,
						),
						'html'    => array(
							'#type'                  => 'textarea',
							'#rows'                  => 3,
							'#default_value'         => isset( $settings['not_found']['html'] ) ? $settings['not_found']['html'] : null,
							'#horizontal'            => true,
							'#states'                => array(
								'visible' => array(
									sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'not_found', 'custom' ) ) ) ) => array(
										'type'  => 'checked',
										'value' => true,
									),
								),
							),
							'#description'           => $application->System_Util_availableTags(
								array(
									'%current_user_id%',
									'%current_user_name%',
									'%current_user_display_name%',
								)
							),
							'#description_no_escape' => true,
						),
					),
				);

				if ( ! empty( $bundle->info['search_enable'] ) ) {
					$form['search'] = array(
						'#type'          => 'checkbox',
						'#title'         => $prefix . __( 'Show search button', 'directories-pro' ),
						'#default_value' => ! empty( $settings['search'] ),
						'#horizontal'    => true,
						'#weight'        => 4,
					);
				}

				if ( $bundle->entitytype_name === 'post'
					&& ! empty( $bundle->info['public'] )
					&& empty( $bundle->info['parent'] )
					&& $application->isComponentLoaded( 'FrontendSubmit' )
				) {
					$form['add']            = array(
						'show'       => array(
							'#type'          => 'checkbox',
							'#title'         => $prefix . sprintf( __( 'Show "%s" button', 'directories-pro' ), $bundle->getLabel( 'add' ) ),
							'#default_value' => ! empty( $settings['add']['show'] ),
							'#horizontal'    => true,
						),
						'show_label' => array(
							'#type'          => 'checkbox',
							'#title'         => $prefix . sprintf( __( 'Show "%s" button with label', 'directories-pro' ), $bundle->getLabel( 'add' ) ),
							'#default_value' => ! empty( $settings['add']['show_label'] ),
							'#horizontal'    => true,
							'#states'        => array(
								'visible' => array(
									sprintf( 'input[name="%s"]', $application->Form_Form_fieldName( array_merge( $parents, array( 'add', 'show' ) ) ) ) => array(
										'type'  => 'checked',
										'value' => true,
									),
								),
							),
						),
					);
					$form['add']['#weight'] = 10;
				}

				return $form;
		}
	}
}
