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

use SabaiApps\Directories\Component\System\Tool\AbstractTool;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\Form\Form;
use SabaiApps\Directories\Context;

class CopyChoiceFieldValuesSystemTool extends AbstractTool {

	protected function _systemToolInfo() {
		return array(
			'label'       => __( 'Copy choice type field values', 'directories-pro' ),
			'description' => __( 'This tool will let you copy field values between Choice type fields.', 'directories-pro' ),
			'weight'      => 100,
			'steps'       => array( 'select_fields' ),
		);
	}

	public function systemToolSettingsForm( $step, array $values, array $parents = array(), ?Context $context = null ) {
		if ( $step === 'select_fields' ) {
			$fields = array();
			foreach ( $this->_application->Entity_Bundles() as $bundle ) {
				if ( ! $options = $this->_application->Entity_Field_options(
					$bundle,
					array(
						'prefix'      => $bundle->getGroupLabel() . ' - ',
						'name_prefix' => $bundle->name . '-',
						'type'        => array( 'choice', 'list' ),
					)
				) ) {
					continue;
				}

				$fields[ $bundle->name ] = $options;
			}
			$form = array(
				'#element_validate' => array(
					function ( Form $form, &$value, $element ) {
						list($bundle_name, $field_name) = explode( '-', $value['field_from'] );
						if ( empty( $value[ $bundle_name ] )
						|| $value['field_from'] === $value[ $bundle_name ]
								) {
								$form->setError( __( 'Source and target fields must be different fields.', 'directories-pro' ) );
						}
					},
				),
				'field_from'        => array(
					'#title'      => __( 'Source field', 'directories-pro' ),
					'#type'       => 'select',
					'#options'    => call_user_func_array( 'array_merge', array_values( $fields ) ),
					'#horizontal' => true,
					'#required'   => true,
				),
			);
			foreach ( array_keys( $fields ) as $bundle_name ) {
				$form[ $bundle_name ] = array(
					'#title'      => __( 'Target field', 'directories-pro' ),
					'#type'       => 'select',
					'#options'    => $fields[ $bundle_name ],
					'#horizontal' => true,
					'#required'   => true,
					'#states'     => array(
						'visible' => array(
							sprintf( 'select[name="%s"]', $this->_application->Form_Form_fieldName( array( $parents, 'field_from' ) ) ) => array(
								'type'  => 'one',
								'value' => array_keys( $fields[ $bundle_name ] ),
							),
						),
					),
				);
			}

			return $form;
		}

		if ( ( ! $fields = $this->_getFields( $values['select_fields'] ) )
			|| ( ! $bundle = $fields[0]->Bundle )
		) {
			return false;
		}

		$form['map_options'] = array(
			'#title' => sprintf(
				__( 'Map choice options from %1$s to %2$s', 'directories-pro' ),
				$bundle->getGroupLabel() . ' - ' . $fields[0]->getFieldLabel(),
				$bundle->getGroupLabel() . ' - ' . $fields[1]->getFieldLabel()
			),
		);
		$from_settings       = $fields[0]->getFieldSettings();
		$from_options        = empty( $from_settings['options']['options'] ) ? array() : $from_settings['options']['options'];
		$to_settings         = $fields[1]->getFieldSettings();
		$to_options          = empty( $to_settings['options']['options'] ) ? array() : $to_settings['options']['options'];
		$to_options          = array( '' => __( '— Select —', 'directories-pro' ) ) + $to_options;
		foreach ( $from_options as $option_name => $option_label ) {
			$form['map_options'][ $option_name ] = array(
				'#type'          => 'select',
				'#title'         => $option_label,
				'#horizontal'    => true,
				'#options'       => $to_options,
				'#default_value' => isset( $to_options[ $option_name ] ) ? $option_name : null,
			);
		}
		return $form;
	}

	protected function _getFields( array $selectedFields ) {
		if ( empty( $selectedFields['field_from'] )
			|| ( ! $field_from_parts = explode( '-', $selectedFields['field_from'] ) )
			|| empty( $selectedFields[ $field_from_parts[0] ] )
			|| ( ! $field_to_parts = explode( '-', $selectedFields[ $field_from_parts[0] ] ) )
			|| ( ! $field_from = $this->_application->Entity_Field( $field_from_parts[0], $field_from_parts[1] ) )
			|| ( ! $field_to = $this->_application->Entity_Field( $field_from_parts[0], $field_to_parts[1] ) )
		) {
			return false;
		}

		return array( $field_from, $field_to );
	}

	public function systemToolInit( array $settings, array &$storage, array &$logs, ?Context $context = null ) {
		if ( ( ! $fields = $this->_getFields( $settings['select_fields'] ) )
			|| ( ! $bundle = $fields[0]->Bundle )
			|| ( ! $count = $this->_application->Entity_Query( $bundle->entitytype_name, $bundle->name )->fieldIsNotNull( $fields[0]->getFieldName(), 'entity_id' )->count() )
		) {
			return false;
		}

		return array( 'default' => $count );
	}

	public function systemToolRunTask( $task, array $settings, $iteration, $total, array &$storage, array &$logs, ?Context $context = null ) {
		if ( ( ! $fields = $this->_getFields( $settings['select_fields'] ) )
			|| ( ! $bundle = $fields[0]->Bundle )
		) {
			return false;
		}

		$paginator = $this->_application->Entity_Query( $bundle->entitytype_name, $bundle->name )
			->fieldIsNotNull( $fields[0]->getFieldName(), 'entity_id' )
			->sortById()
			->paginate( 50, 0 )
			->setCurrentPage( $iteration );
		foreach ( $paginator->getElements() as $entity ) {
			if ( ! $values = $entity->getFieldValue( $fields[0]->getFieldName() ) ) {
				continue;
			}

			$new_values = array();
			foreach ( $values as $value ) {
				if ( isset( $settings['map_options'][ $value ] ) ) {
					$new_values[] = $settings['map_options'][ $value ];
				}
			}
			try {
				$this->_application->Entity_Save(
					$entity,
					array(
						$fields[1]->getFieldName() => $new_values,
					)
				);
			} catch ( Exception\IException $e ) {
				$logs['error'][] = $e->getMessage();
			}
		}

		$offset            = $paginator->getElementOffset();
		$logs['success'][] = sprintf(
			'Copy done for %d - %d',
			$offset + 1,
			$offset + $paginator->getElementLimit()
		);

		return $paginator->getElementLimit();
	}
}
