<?php

class HappyForms_Part_CheckboxExtended extends HappyForms_Part_Checkbox {

	private $class_name = 'HappyForms_Part_CheckboxExtended';

	public function __construct() {
		parent::__construct();
	}

	public function hook() {
		remove_filter( 'happyforms_stringify_part_value', array( self::$parent, 'stringify_value' ), 10, 3 );

		add_filter( 'happyforms_part_input_after', array( $this, 'append_input' ), 10, 2 );
		add_filter( 'happyforms_stringify_part_value', array( $this, 'stringify_value' ), 10, 3 );
		add_filter( 'happyforms_frontend_dependencies', array( $this, 'script_dependencies' ), 10, 2 );
		add_filter( 'happyforms_part_class', array( $this, 'html_part_class' ), 10, 3 );
		add_filter( 'happyforms_part_frontend_template_path_checkbox', array( $this, 'set_template_path' ) );
		add_filter( 'happyforms_validate_part', array( $this, 'validate_part' ) );
	}

	public function get_customize_fields() {
		$fields = parent::get_customize_fields();

		$fields['other_option'] = array(
			'default' => 0,
			'sanitize' => 'happyforms_sanitize_checkbox'
		);

		$fields['other_option_label'] = array(
			'default' => __( 'Other', 'happyforms' ),
			'sanitize' => 'sanitize_text_field'
		);

		$fields['other_option_placeholder'] = array(
			'default' => '',
			'sanitize' => 'sanitize_text_field'
		);

		$fields['display_as_letters'] = array(
			'default' => 0,
			'sanitize' => 'happyforms_sanitize_checkbox'
		);

		$fields['limit_choices'] = array(
			'default' => 0,
			'sanitize' => 'happyforms_sanitize_checkbox'
		);

		$fields['limit_choices_min'] = array(
			'default' => 1,
			'sanitize' => 'intval'
		);

		$fields['limit_choices_max'] = array(
			'default' => 1,
			'sanitize' => 'intval'
		);

		return happyforms_get_part_customize_fields( $fields, $this->type );
	}

	public function sanitize_value( $part = array(), $form = array(), $request = array() ) {
		$sanitized_value = $this->get_default_value( $part );
		$part_name = happyforms_get_part_name( $part, $form );

		if ( isset( $request[$part_name] ) ) {
			$requested_data = $request[$part_name];

			$filtered_request = array_map( 'json_decode', array_map( 'stripslashes', $requested_data ) );
			$contains_array = array_map( 'is_array', $filtered_request );

			if ( ! in_array( true, $contains_array ) ) {
				$sanitized_value = parent::sanitize_value( $part, $form, $request );
			} else {
				foreach ( $filtered_request as $index => $request ) {
					if ( is_array( $request ) ) {
						$filtered_request[$index][0] = intval( $filtered_request[$index][0] );
						$filtered_request[$index][1] = sanitize_text_field( $filtered_request[$index][1] );
					} else {
						$filtered_request[$index] = intval( $filtered_request[$index] );
					}
				}

				$sanitized_value = $filtered_request;
			}
		}

		return $sanitized_value;
	}

	public function validate_value( $value, $part = array(), $form = array() ) {
		$validated_value = $value;

		if ( 1 === $part['required'] && empty( $validated_value ) ) {
			$validated_value = new WP_Error( 'error', happyforms_get_validation_message( 'no_selection' ) );
			return $validated_value;
		}

		if ( 1 === $part['limit_choices'] ) {
			if ( count( $validated_value ) < $part['limit_choices_min'] ) {
				return new WP_Error( 'error', happyforms_get_validation_message( 'select_more_choices' ) );
			}

			if ( count( $validated_value ) > $part['limit_choices_max'] ) {
				return new WP_Error( 'error', happyforms_get_validation_message( 'select_less_choices' ) );
			}
		}

		if ( ! is_array( $validated_value ) && 1 !== $part['required'] ) {
			return $validated_value;
		}

		$contains_array = array_map( 'is_array', $validated_value );

		if ( ! in_array( true, $contains_array ) ) {
			$validated_value = parent::validate_value( $value, $part, $form );

			if ( is_wp_error( $validated_value ) ) {
				return $validated_value;
			}

			foreach ( $validated_value as $value ) {
				$value = $this->validate_option_limits( $value, $part, $form );

				if ( is_wp_error( $value ) ) {
					return $value;
				}
			}
		}

		$numeric_values = array_filter( $validated_value, 'is_int' );
		$array_values = array_filter( $validated_value, 'is_array' );
		$options = range( 0, count( $part['options'] ) - 1 );
		$intersection = array_intersect( $options, $numeric_values );

		if ( count( $numeric_values ) !== count( $intersection ) ) {
			return new WP_Error( 'error', happyforms_get_validation_message( 'field_invalid' ) );
		}

		foreach ( $numeric_values as $numeric_value ) {
			$validated_numeric_value = $this->validate_option_limits( $numeric_value, $part, $form );

			if ( is_wp_error( $validated_numeric_value ) ) {
				return $validated_numeric_value;
			}
		}

		foreach ( $array_values as $array_value ) {
			if ( 1 === $part['required'] && ! isset( $array_value[1] ) ) {
				$validated_value = new WP_Error( 'error', happyforms_get_validation_message( 'field_empty' ) );
				return $validated_value;
			}
		}

		foreach ( $validated_value as $key => $value ) {
			if ( is_array( $validated_value[ $key ] ) ) {
				foreach ( $validated_value[$key] as $opt_key  => $opt_val ) {
					if ( '' == $validated_value[$key][$opt_key] ) {
						return new WP_Error( 'error', happyforms_get_validation_message( 'field_invalid' ) );
					}
				}
			}
		}

		return $validated_value;
	}

	public function stringify_value( $value, $part, $form, $force = false ) {
		if ( $this->type === $part['type'] || $force ) {
			if ( empty( $value ) ) {
				return $value;
			}
			$original_value = $value;
			$options = happyforms_get_part_options( $part['options'], $part, $form );
			$labels = wp_list_pluck( $options, 'label' );
			$contains_array = array_map( 'is_array', $value );

			if ( ! in_array( true, $contains_array ) ) {
				$value = parent::stringify_value( $value, $part, $form, $force );

				if ( $this->display_choices_as_letters( $part ) ) {
					$values = array();
					foreach ( $original_value as $option_index ) {
						if ( isset( $part['options'][(int) $option_index] ) ) {
							$option = $part['options'][(int) $option_index];
							$letter = happyforms_get_part_choice_letter( $option, $part );
							$values[] = "{$letter}) {$option['label']}";
						}
					}

					$value = implode( ', ', $values );
				}
			} else {
				foreach ( $value as $i => $index ) {
					$label = '';

					if ( is_array( $index ) && ! empty( $index[1] ) ) { // other option
						$value[$i] = $index[1];

						if ( $this->display_choices_as_letters( $part ) ) {
							$letter = happyforms_get_part_choice_letter( '', $part );
							$label = $value[$i];
						}
					} else { // standard option
						$value[$i] = $options[$index]['label'];

						if ( $this->display_choices_as_letters( $part ) ) {
							if ( isset( $part['options'][$index] ) ) {
								$option = $part['options'][$index];
								$letter = happyforms_get_part_choice_letter( $option, $part );
								$label = $option['label'];
							}
						}
					}

					if ( $this->display_choices_as_letters( $part ) ) {
						$value[$i] = "{$letter}) {$label}";
					}
				}
			}
		}

		return $value;
	}

	public function append_input( $part, $form ) {
		if ( $this->type !== $part['type'] ) {
			return;
		}

		if ( 1 == $part['other_option'] ) {
			require( happyforms_get_include_folder() . '/templates/parts/frontend-checkbox-other-option.php' );
		}
	}

	public function script_dependencies( $deps, $forms ) {
		$contains_radio = false;
		$form_controller = happyforms_get_form_controller();

		foreach ( $forms as $form ) {
			if ( $form_controller->get_first_part_by_type( $form, $this->type ) ) {
				$contains_radio = true;
				break;
			}
		}

		if ( ! happyforms_is_preview() && ! $contains_radio ) {
			return $deps;
		}

		wp_register_script(
			'happyforms-checkbox-ext',
			happyforms_get_plugin_url() . 'inc/assets/js/frontend/checkbox-extended.js',
			array(), HAPPYFORMS_VERSION, true
		);

		$deps[] = 'happyforms-checkbox-ext';

		return $deps;
	}

	public function customize_enqueue_scripts( $deps = array() ) {
		parent::customize_enqueue_scripts( $deps );

		wp_enqueue_script(
			'part-checkbox-extended',
			happyforms_get_plugin_url() . 'inc/assets/js/parts/part-checkbox-extended.js',
			$deps, HAPPYFORMS_VERSION, true
		);
	}

	public function html_part_class( $class, $part, $form ) {
		parent::html_part_class( $class, $part, $form );

		if ( $this->type === $part['type'] ) {
			if ( $this->display_choices_as_letters( $part ) ) {
				$class[] = 'happyforms-part-choice--display-as-letters';
			}
		}

		return $class;
	}

	public function set_template_path( $template_path ) {
		$template_path = happyforms_get_include_folder() . '/templates/parts/frontend-checkbox-extended.php';

		return $template_path;
	}

	public function display_choices_as_letters( $part ) {
		if ( 1 == $part['display_as_letters'] ) {
			return true;
		}

		return false;
	}

	public function validate_part( $part_data ) {
		if ( $this->type !== $part_data['type'] ) {
			return $part_data;
		}

		$min_choices = $part_data['limit_choices_min'];
		$max_choices = $part_data['limit_choices_max'];

		$min_choices = intval( $min_choices );
		$max_choices = intval( $max_choices );

		if ( 0 == $min_choices && 1 == $part_data['required'] ) {
			$part_data['limit_choices_min'] = 1;
		}

		if ( $max_choices < $min_choices || $max_choices > count( $part_data['options'] ) ) {
			$part_data['limit_choices_max'] = count( $part_data['options'] );
		}

		return $part_data;
	}

	private function validate_option_limits( $value, $part, $form ) {
		foreach( $part['options'] as $o => $option ) {
			$option = wp_parse_args( $option, happyforms_upgrade_get_option_limiter()->get_option_fields() );

			if ( ! $option['limit_submissions'] || $o !== intval( $value ) ) {
				continue;
			}

			$limit = intval( $option['limit_submissions_amount'] );
			$form_id = $form['ID'];
			$option_id = $option['id'];
			$count = happyforms_get_message_controller()->count_by_option( $form_id, $option_id, $limit );

			if ( $count === $limit ) {
				return new WP_Error( 'error', happyforms_get_validation_message( 'field_invalid' ) );
			}
		}

		return $value;
	}

}
