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

use SabaiApps\Directories\Component\Form\Form;

/**
 * OptionsField provides a configurable set of selectable options.
 * Supports icons, colors, CSV import, validation, and dynamic add/remove/sort.
 */
class OptionsField extends AbstractField {

	/**
	 * Initializes the Options field with options, icons, colors, and default values.
	 *
	 * @param string $name
	 * @param array  $data
	 * @param Form   $form
	 */
	public function formFieldInit( $name, array &$data, Form $form ) {
		if ( ! isset( $data['#id'] ) ) {
			$data['#id'] = $form->getFieldId( $name );
		}
		// If default_value is an array with options, extract options, icons, colors, and default values
		if ( isset( $data['#default_value']['options'] ) ) {
			$data['#options']       = $data['#default_value']['options'];
			$data['#icons']         = isset( $data['#default_value']['icons'] ) ? $data['#default_value']['icons'] : array();
			$data['#colors']        = isset( $data['#default_value']['colors'] ) ? $data['#default_value']['colors'] : array();
			$data['#default_value'] = isset( $data['#default_value']['default'] ) ? $data['#default_value']['default'] : array();
		} else {
			if ( ! isset( $data['#options'] ) ) {
				$data['#options'] = array();
			}
			if ( ! isset( $data['#icons'] ) ) {
				$data['#icons'] = array();
			}
			if ( ! isset( $data['#colors'] ) ) {
				$data['#colors'] = array();
			}
			if ( ! isset( $data['#default_value'] ) ) {
				$data['#default_value'] = array();
			}
		}
		// Register pre-render callback with icon and color picker flags
		$form->settings['#pre_render'][ __CLASS__ ] = array( array( $this, 'preRenderCallback' ), array( empty( $data['#disable_icon'] ), ! empty( $data['#enable_color'] ) ) );
	}

	/**
	 * Loads options from CSV data if provided.
	 *
	 * @param array $value
	 */
	protected function _loadCsvData( &$value ) {
		$value['csv'] = trim( $value['csv'] );
		if ( ! strlen( $value['csv'] ) ) {
			return;
		}

		foreach ( explode( PHP_EOL, $value['csv'] ) as $line ) {
			if ( ! $line = trim( $line ) ) {
				continue;
			}

			$_line = array_map( 'trim', explode( ',', $line ) );
			if ( ! isset( $_line[0] )
				|| ! strlen( $_line[0] )
			) {
				continue;
			}

			$icon = $color = null;
			if ( isset( $_line[2] ) ) {
				if ( strlen( $_line[2] ) ) {
					if ( strpos( $_line[2], 'far' ) !== false
						|| strpos( $_line[2], 'fas' ) !== false
						|| strpos( $_line[2], 'fab' ) !== false
					) {
						$icon = $_line[2];
					} elseif ( strpos( $_line[2], 'fa-' ) === 0 ) {
							$icon = 'fas ' . $_line[2];
					}
				}
				if ( isset( $_line[3] )
					&& strlen( $_line[3] )
					&& $this->_isValidColor( $_line[3] )
				) {
					$color = $_line[3];
				}
			}
			$value['options'][] = array(
				'label'      => $_line[0],
				'value'      => isset( $_line[1] ) && strlen( $_line[1] ) ? $_line[1] : $_line[0],
				'icon'       => $icon,
				'color'      => $color,
				'is_default' => ! isset( $_line[4] ) || ! strlen( $_line[4] ) || ! empty( $_line[4] ), // false only if "0"
			);
		}
	}

	/**
	 * Checks if a string is a valid hex color.
	 *
	 * @param string $color
	 * @return bool
	 */
	protected function _isValidColor( $color ) {
		return ( $length = strlen( $color ) )
			&& ( $length === 4 || $length === 7 )
			&& strpos( $color, '#' ) === 0
			&& ctype_xdigit( substr( $color, 1 ) );
	}

	/**
	 * Handles value processing, validation, and normalization for the Options field on submit.
	 *
	 * @param mixed $value
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldSubmit( &$value, array &$data, Form $form ) {
		if ( isset( $value['csv'] ) ) {
			$this->_loadCsvData( $value );
		}
		$options       = $icons = $colors = array();
		$default_value = array();
		if ( ! isset( $value['default'] ) ) {
			$value['default'] = array();
		} else {
			settype( $value['default'], 'array' );
		}
		// Add disabled options that are selected by default
		if ( ! empty( $data['#options_disabled'] ) && ! empty( $data['#default_value'] ) ) {
			foreach ( $data['#options_disabled'] as $option_disabled ) {
				if ( in_array( $option_disabled, $data['#default_value'] ) ) {
					$default_value[] = $option_disabled;
				}
			}
		}
		// Set up value regex if slugify is enabled
		if ( ! empty( $data['#slugify_value'] ) && ! isset( $data['#value_regex'] ) ) {
			$data['#value_regex'] = '/^[a-z0-9_]+$/';
			if ( ! isset( $data['#value_regex_error_message'] ) ) {
				$data['#value_regex_error_message'] = __( 'Only lowercase alphanumeric characters and underscores are allowed for option values.', 'directories-pro' );
			}
		}
		foreach ( (array) @$value['options'] as $key => $option ) {
			$option['value'] = trim( $option['value'] );
			if ( ! strlen( $option['value'] ) ) {
				continue;
			}

			// Validate value with regex or max length
			if ( isset( $data['#value_regex'] ) && strlen( $data['#value_regex'] ) ) {
				if ( ! preg_match( $data['#value_regex'], $option['value'] ) ) {
					$error = isset( $data['#value_regex_error_message'] )
						? $data['#value_regex_error_message']
						: sprintf( __( 'The input value did not match the regular expression: %s', 'directories-pro' ), $data['#value_regex'] );
					$form->setError( $error, $data );
				}
			} elseif ( ! empty( $data['#value_max_length'] ) ) {
				if ( strlen( $option['value'] ) > $data['#value_max_length'] ) {
					$form->setError( sprintf( __( 'The input value must be shorter than %d characters.', 'directories-pro' ), $data['#value_max_length'] ), $data );
				}
			}

			// Prevent duplicate values by appending a suffix
			if ( isset( $options[ $option['value'] ] ) ) {
				$suffix = 2;
				while ( isset( $options[ $option['value'] . $suffix ] ) ) {
					++$suffix;
				}
				$option['value'] .= $suffix;
			}
			// Mark as default if checked or flagged as default
			if ( ( in_array( $key, $value['default'] ) || ! empty( $option['is_default'] ) )
				&& ! in_array( $option['value'], $default_value )
			) {
				$options[ $option['value'] ] = isset( $option['label'] ) ? $option['label'] : null; // may be empty if option is disabled
				$default_value[]             = $option['value'];
			} elseif ( empty( $data['#default_options_only'] ) ) {
					$options[ $option['value'] ] = isset( $option['label'] ) ? $option['label'] : null; // may be empty if option is disabled

			}
			if ( ! empty( $option['icon'] ) ) {
				$icons[ $option['value'] ] = $option['icon'];
			}
			if ( isset( $option['color'] )
				&& $this->_isValidColor( $color = trim( $option['color'] ) )
			) {
				$colors[ $option['value'] ] = $option['color'];
			}
		}

		// Final validation for required fields and default selection
		if ( ! $form->hasError( $data ) ) {
			if ( empty( $options ) ) {
				if ( $form->isFieldRequired( $data ) ) {
					$form->setError( isset( $data['#required_error_message'] ) ? $data['#required_error_message'] : __( 'Please fill out this field.', 'directories-pro' ), $data );
				}
			} elseif ( empty( $default_value )
					&& ! empty( $data['#require_default'] )
				) {

					$form->setError( isset( $data['#default_required_error_message'] ) ? $data['#default_required_error_message'] : __( 'Please select at least one option.', 'directories-pro' ), $data );
			}
		}

		$value = empty( $data['#default_options_only'] ) ? array(
			'options' => $options,
			'icons'   => $icons,
			'colors'  => $colors,
			'default' => $default_value,
		) : $options;
	}

	/**
	 * Renders the Options field as a list of option inputs with icons, colors, and controls.
	 *
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldRender( array &$data, Form $form ) {
		if ( ! empty( $data['#multiple'] ) ) {
			$type         = 'checkbox';
			$default_name = '[default][]';
		} else {
			$type         = 'radio';
			$default_name = '[default]';
		}
		$input   = array( '<div class="%18$sinput-group drts-form-field-option%15$s %18$smb-2">' );
		$input[] = $checkbox = '<div class="%18$sinput-group-text"><input type="%9$s" name="%1$s%10$s" id="%6$s-%2$d" data-option-value="%4$s" value="%2$d"%5$s%14$s /></div>';
		if ( empty( $data['#disable_icon'] ) ) {
			$input[] = '<button type="button" name="%1$s[options][%2$d][icon]" data-current="%16$s" class="%18$sbtn %18$sbtn-info drts-form-field-option-icon" data-bs-placement="bottom"></button>';
		}
		if ( ! empty( $data['#enable_color'] ) ) {
			$input[] = '<input type="text" name="%1$s[options][%2$d][color]" value="%21$s" class="%18$sform-control drts-form-field-option-color" placeholder="%22$s" />';
		}
		$input[]          = '<input type="text" name="%1$s[options][%2$d][label]" value="%3$s" placeholder="%7$s" class="%18$sform-control drts-form-field-option-label"%19$s />';
		$value_input_type = empty( $data['#hide_value'] ) ? 'text' : 'hidden';
		$input[]          = '<input type="' . $value_input_type . '" name="%1$s[options][%2$d][value]" value="%4$s" placeholder="%8$s" class="%18$sform-control drts-form-field-option-value" data-slugify="%17$s" />';
		if ( empty( $data['#disable_add'] ) ) {
			$checked = empty( $data['#default_unchecked'] ) && $type === 'checkbox';
			$input[] = '<a href="#" class="%18$sbtn %18$sbtn-success" onclick="DRTS.Form.field.options.add(\'#%6$s\', \'%1$s\', this, %11$s, ' . ( $checked ? 'true' : 'false' ) . '); return false;"><i class="fas fa-plus"></i></a>';
		} elseif ( ! isset( $data['#disable_remove'] ) ) {
				$data['#disable_remove'] = true;
		}
		if ( empty( $data['#disable_remove'] ) ) {
			$input[] = '<a href="#" class="%18$sbtn %18$sbtn-danger" onclick="DRTS.Form.field.options.remove(\'#%6$s\', this, \'%12$s\'); return false;"><i class="fas fa-minus"></i></a>';
		}
		if ( empty( $data['#disable_sort'] ) ) {
			$input[] = '<span class="%18$sbtn %18$sbtn-secondary drts-form-field-option-sort%13$s"><i class="fas fa-arrows-up-down"></i></span>';
		}
		$input[] = '</div>';
		$input   = implode( '', $input );

		$inputs        = array();
		$label_title   = $this->_application->H( isset( $data['#label_title'] ) ? (string) $data['#label_title'] : __( 'Label', 'directories-pro' ) );
		$value_title   = $this->_application->H( isset( $data['#value_title'] ) ? (string) $data['#value_title'] : __( 'Value', 'directories-pro' ) );
		$icon_title    = $this->_application->H( isset( $data['#icon_title'] ) ? (string) $data['#icon_title'] : __( 'Icon', 'directories-pro' ) );
		$color_title   = $this->_application->H( isset( $data['#color_title'] ) ? (string) $data['#color_title'] : __( 'Color', 'directories-pro' ) );
		$checked_title = $this->_application->H( isset( $data['#checked_title'] ) ? (string) $data['#checked_title'] : _x( 'Checked', 'whether checked by default or not', 'directories-pro' ) );
		$optional_text = __( '(optional)', 'directories-pro' );

		if ( ! empty( $data['#options'] ) ) {
			$first_option = current( $data['#options'] );
			if ( ! is_array( $first_option ) ) {
				// If options are not arrays, convert to array format
				$new_options = array();
				foreach ( $data['#options'] as $value => $label ) {
					$new_options[] = array(
						'value' => $value,
						'label' => $label,
						'icon'  => isset( $data['#icons'][ $value ] ) ? $data['#icons'][ $value ] : null,
						'color' => isset( $data['#colors'][ $value ] ) ? $data['#colors'][ $value ] : null,
					);
				}
				$data['#options'] = $new_options;
			}
			// Normalize default values if form is submitted
			if ( $form->isSubmitted() ) {
				foreach ( array_keys( $data['#default_value'] ) as $key ) {
					$value = $data['#default_value'][ $key ];
					if ( is_numeric( $value )
						&& isset( $data['#options'][ $value ] )
					) {
						$data['#default_value'][ $key ] = $data['#options'][ $value ]['value'];
					} else {
						break; // not submit and error so abort
					}
				}
			}
			// Prepare disabled, sort-disabled, and label-disabled options
			if ( $options_value_disabled = isset( $data['#options_value_disabled'] ) ? $data['#options_value_disabled'] : array() ) {
				$input_disabled   = array( '<div class="%18$sinput-group drts-form-field-option %18$smb-2 drts-form-field-option-disabled">' );
				$input_disabled[] = $checkbox;
				if ( empty( $data['#disable_icon'] ) ) {
					$input_disabled[] = '<button type="button" name="%1$s[options][%2$d][icon]" data-current="%16$s" class="%18$sbtn %18$sbtn-info drts-form-field-option-icon" data-bs-placement="bottom"></button>';
				}
				if ( ! empty( $data['#enable_color'] ) ) {
					$input_disabled[] = '<input type="text" name="%1$s[options][%2$d][color]" value="" class="%18$sform-control drts-form-field-option-color" placeholder="%22$s" />';
				}
				$input_disabled[] = '<input type="text" name="%1$s[options][%2$d][label]" value="%3$s" placeholder="%7$s" class="%18$sform-control drts-form-field-option-label"%19$s />';
				$input_disabled[] = '<input type="' . $value_input_type . '" value="%4$s" placeholder="%8$s" disabled="disabled" class="%18$sform-control" /><input type="hidden" name="%1$s[options][%2$d][value]" value="%4$s" class="drts-form-field-option-value" data-slugify="%17$s" />';
				if ( empty( $data['#disable_add'] ) ) {
					$input_disabled[] = '<a href="#" class="%18$sbtn %18$sbtn-success %18$sdisabled" onclick="return false;"><i class="fas fa-plus"></i></a>';
				}
				if ( empty( $data['#disable_remove'] ) ) {
					$input_disabled[] = '<a href="#" class="%18$sbtn %18$sbtn-danger%20$s" onclick="return false;"><i class="fas fa-minus"></i></a>';
				}
				if ( empty( $data['#disable_sort'] ) ) {
					$input_disabled[] = '<span class="%18$sbtn %18$sbtn-secondary drts-form-field-option-sort%13$s"><i class="fas fa-arrows-up-down"></i></span>';
				}
				$input_disabled[] = '</div>';
				$input_disabled   = implode( '', $input_disabled );
			}
			$options_disabled       = isset( $data['#options_disabled'] ) ? $data['#options_disabled'] : array();
			$options_sort_disabled  = isset( $data['#options_sort_disabled'] ) ? $data['#options_sort_disabled'] : array();
			$options_label_disabled = isset( $data['#options_label_disabled'] ) ? $data['#options_label_disabled'] : array();
			foreach ( $data['#options'] as $key => $option ) {
				if ( ! strlen( $option['value'] ) ) {
					continue;
				}

				$option_disabled        = $options_value_disabled === true || in_array( $option['value'], $options_value_disabled );
				$option_remove_disabled = $option_disabled
					&& isset( $data['#options_remove_disabled'] )
					&& ( $data['#options_remove_disabled'] === true || in_array( $key, $data['#options_remove_disabled'] ) );
				$inputs[]               = sprintf(
					$option_disabled ? $input_disabled : $input,
					$data['#name'],
					$key,
					isset( $option['label'] ) ? $this->_application->H( $option['label'] ) : '',
					$this->_application->H( $option['value'] ),
					in_array( $option['value'], $data['#default_value'] ) ? ' checked="checked"' : '',
					$data['#id'],
					isset( $data['#options_placeholder'][ $option['value'] ] ) ? $data['#options_placeholder'][ $option['value'] ] : $label_title,
					isset( $data['#options_value_placeholder'][ $option['value'] ] ) ? $data['#options_value_placeholder'][ $option['value'] ] : $value_title,
					$type,
					$default_name,
					$type === 'checkbox' ? 'true' : 'false',
					__( 'Are you sure?', 'directories-pro' ),
					in_array( $option['value'], $options_sort_disabled ) ? ' ' . DRTS_BS_PREFIX . 'disabled' : '',
					in_array( $option['value'], $options_disabled ) ? ' disabled="disabled"' : '',
					'',
					isset( $option['icon'] ) ? $this->_application->H( $option['icon'] ) : '',
					empty( $data['#slugify_value'] ) ? 'false' : 'true',
					DRTS_BS_PREFIX,
					in_array( $option['value'], $options_label_disabled ) ? ' disabled="disabled"' : '',
					$option_remove_disabled ? ' ' . DRTS_BS_PREFIX . 'disabled' : '', // disable remove button?
					! empty( $option['color'] ) ? $this->_application->H( $option['color'] ) : '',
					$color_title
				);
			}
			if ( empty( $data['#disable_add'] ) ) {
				$inputs[] = sprintf(
					$input,
					$data['#name'],
					++$key,
					'',
					'',
					$type === 'checkbox' ? ' checked="checked"' : '',
					$data['#id'],
					$label_title,
					$value_title,
					$type,
					$default_name,
					$type === 'checkbox' ? 'true' : 'false',
					__( 'Are you sure?', 'directories-pro' ),
					'',
					in_array( $option['value'], $options_disabled ) ? ' disabled="disabled"' : '',
					' drts-form-field-option-new',
					'',
					empty( $data['#slugify_value'] ) ? 'false' : 'true',
					DRTS_BS_PREFIX,
					'',
					'', // disable remove button?
					'',
					$color_title
				);
			}
		} else {
			// Render empty option rows if no options exist
			if ( empty( $data['#disable_add'] ) ) {
				for ( $i = 0; $i < 3; $i++ ) {
					$inputs[] = sprintf(
						$input,
						$data['#name'],
						$i,
						'',
						'',
						( $type === 'checkbox' && empty( $data['#default_unchecked'] ) ) || ( $type === 'radio' && $i === 0 ) ? ' checked="checked"' : '',
						$data['#id'],
						$label_title,
						$value_title,
						$type,
						$default_name,
						$type === 'checkbox' ? 'true' : 'false',
						__( 'Are you sure?', 'directories-pro' ),
						'',
						'',
						' drts-form-field-option-new',
						'',
						empty( $data['#slugify_value'] ) ? 'false' : 'true',
						DRTS_BS_PREFIX,
						'',
						'', // disable remove button?
						'',
						$color_title
					);
				}
			}
		}
		$markup = array( '<div class="drts-form-field-options">' );
		if ( empty( $inputs ) ) {
			if ( isset( $data['#empty_message'] ) ) {
				$markup[] = $data['#empty_message'];
			}
		} else {
			$markup[] = implode( '', $inputs );
		}
		// Add CSV import button and textarea if enabled
		if ( empty( $data['#disable_add'] ) && empty( $data['#disable_add_csv'] ) ) {
			$markup[] = '<button type="button" class="' . DRTS_BS_PREFIX . 'btn ' . DRTS_BS_PREFIX . 'btn-sm ' . DRTS_BS_PREFIX . 'btn-outline-secondary drts-form-field-option-csv"><i class="fas fa-plus"></i> ' . __( 'Add from CSV', 'directories-pro' ) . '</button>';
			$markup[] = sprintf(
				'<textarea placeholder="%s" name="%s[csv]" rows="2" style="margin-top:10px; width:100%%; display:none;"></textarea>',
				str_repeat(
					$label_title . ',' . $value_title . ' ' . $optional_text
						. ',' . $icon_title . ' ' . $optional_text
						. ',' . $color_title . ' ' . $optional_text
						. ',' . $checked_title . ' ' . $optional_text
						. PHP_EOL,
					2
				),
				$data['#name']
			);
		}
		$markup[] = '</div>';

		$this->_render( implode( '', $markup ), $data, $form );
	}

	/**
	 * Pre-render callback to load scripts and initialize icon and color pickers.
	 *
	 * @param Form $form
	 * @param bool $loadIconPicker
	 * @param bool $loadColorPicker
	 */
	public function preRenderCallback( Form $form, $loadIconPicker, $loadColorPicker ) {
		$this->_application->getPlatform()->loadJqueryUiJs( array( 'sortable' ) )
			->addJsFile( 'form-field-options.min.js', 'drts-form-field-options', array( 'drts-form' ) )
			->addJsFile( 'latinise.min.js', 'latinise', null, null, true, true );
		if ( $loadIconPicker ) {
			$this->_application->Form_Scripts_iconpicker( array( 'fontawesome' ) );
		}
		if ( $loadColorPicker ) {
			$this->_application->Form_Scripts_colorpicker();
		}

		$form->settings['#js_ready'][] = sprintf(
			'(function() {
    $("#%s").find(".drts-form-type-options").each(function(){
        DRTS.Form.field.options($(this)); 
    });
})();',
			$form->settings['#id']
		);
	}
}
