<?php

namespace Limb_Chatbot\Includes\Services\Actions\Parameter_Types;

use Limb_Chatbot\Includes\Data_Objects\Parameter;

/**
 * Class Buttons_Parameter_Type
 *
 * Handles buttons/choice parameter validation and sanitization.
 * Allows users to select from predefined options stored in the config field.
 * Each option can have a label, emoji, and optional tooltip.
 *
 * Config structure example:
 * {
 *   "is_multiselect": false,
 *   "options": [
 *     {
 *       "value": "vegetarian",
 *       "label": "🥗 Vegetarian",
 *       "tooltip": "Plant-based options"
 *     },
 *     {
 *       "value": "vegan",
 *       "label": "🌱 Vegan",
 *       "tooltip": "100% plant-based"
 *     }
 *   ]
 * }
 *
 * When `is_multiselect` is true, the stored value is comma-separated option values (values must not contain commas).
 *
 * @package Limb_Chatbot\Includes\Services\Actions\Parameter_Types
 * @since 1.0.0
 */
class Buttons_Parameter_Type extends Abstract_Parameter_Type {

	/**
	 * Whether this field accepts multiple selections (comma-separated values).
	 *
	 * @param  Parameter  $parameter  Parameter instance.
	 * @return bool
	 */
	private function is_multiselect( Parameter $parameter ): bool {
		$config = $parameter->get_config();
		if ( ! isset( $config['is_multiselect'] ) ) {
			return false;
		}

		return filter_var( $config['is_multiselect'], FILTER_VALIDATE_BOOLEAN );
	}

	/**
	 * @inheritDoc
	 */
	public function get_type(): string {
		return Parameter::TYPE_BUTTONS;
	}

	/**
	 * @inheritDoc
	 */
	public function sanitize( string $value, Parameter $parameter ): string {
		$value = trim( $value );

		if ( $this->is_multiselect( $parameter ) ) {
			if ( '' === $value ) {
				return '';
			}
			$parts    = array_map( 'trim', explode( ',', $value ) );
			$parts    = array_filter( $parts, 'strlen' );
			$seen     = array();
			$sanitized = array();
			foreach ( $parts as $part ) {
				$one = $this->sanitize_single_choice( $part, $parameter );
				if ( '' !== $one && ! in_array( $one, $seen, true ) ) {
					$seen[]      = $one;
					$sanitized[] = $one;
				}
			}

			return implode( ',', $sanitized );
		}

		return $this->sanitize_single_choice( $value, $parameter );
	}

	/**
	 * Map one user token to the canonical option `value`.
	 *
	 * @param  string  $value  Raw token.
	 * @param  Parameter  $parameter  Parameter configuration.
	 * @return string Canonical value or original if no match.
	 */
	private function sanitize_single_choice( string $value, Parameter $parameter ): string {
		$value  = trim( $value );
		$config = $parameter->get_config();
		if ( ! empty( $config['options'] ) && is_array( $config['options'] ) ) {
			foreach ( $config['options'] as $option ) {
				// Match by value (exact, case-insensitive)
				if ( ! empty( $option['value'] ) && strtolower( $option['value'] ) === strtolower( $value ) ) {
					return $option['value'];
				}

				// Match by label (exact match for emoji or case-insensitive for text)
				if ( ! empty( $option['label'] ) ) {
					// First try exact match (handles emoji perfectly)
					if ( $option['label'] === $value ) {
						return $option['value'] ?? $value;
					}

					// Then try case-insensitive match (for text labels)
					if ( strtolower( $option['label'] ) === strtolower( $value ) ) {
						return $option['value'] ?? $value;
					}
				}
			}
		}

		// Return original value if no match found (validation will handle it)
		return $value;
	}

	/**
	 * @inheritDoc
	 */
	public function validate( string $value, Parameter $parameter ): bool {
		$this->clear_errors();

		$trimmed_value = trim( $value );

		// Check if field is empty
		if ( empty( $trimmed_value ) ) {
			// If empty and required, show required error
			if ( $this->is_required( $parameter ) ) {
				$this->add_error( sprintf(
					__( '%s is required.', 'limb-chatbot' ),
					$this->get_label( $parameter )
				) );

				return false;
			}

			// If empty and not required, it's valid
			return true;
		}

		if ( $this->is_multiselect( $parameter ) ) {
			$parts = array_map( 'trim', explode( ',', $trimmed_value ) );
			$parts = array_filter( $parts, 'strlen' );
			foreach ( $parts as $part ) {
				if ( ! $this->validate_option_exists( $part, $parameter ) ) {
					return false;
				}
			}

			return true;
		}

		// Validate that the value matches one of the allowed options
		return $this->validate_option_exists( $trimmed_value, $parameter );
	}

	/**
	 * Validate that the provided value is one of the allowed options
	 *
	 * @param  string  $value  Value to validate
	 * @param  Parameter  $parameter  Parameter configuration
	 *
	 * @return bool True if value is a valid option, false otherwise
	 * @since 1.0.0
	 */
	private function validate_option_exists( string $value, Parameter $parameter ): bool {
		$config = $parameter->get_config();

		if ( empty( $config['options'] ) || ! is_array( $config['options'] ) ) {
			$this->add_error( sprintf(
				__( 'No valid options configured for %s.', 'limb-chatbot' ),
				$this->get_label( $parameter )
			) );

			return false;
		}

		$value = trim( $value );
		$value_lower = strtolower( $value );
		foreach ( $config['options'] as $option ) {
			// Check if value matches option value (exact match)
			if ( ! empty( $option['value'] ) && strtolower( $option['value'] ) == $value_lower ) {
				return true;
			}

			// Check if value matches option label (exact match for emoji or case-insensitive for text)
			if ( ! empty( $option['label'] ) ) {
				// Exact match (handles emoji perfectly)
				if ( $option['label'] === $value ) {
					return true;
				}
				
				// Case-insensitive match (for text labels)
				if ( strtolower( $option['label'] ) === $value_lower ) {
					return true;
				}
			}
		}

		$this->add_error( sprintf(
			__( 'There is not such %s option.', 'limb-chatbot' ),
			strtolower( $this->get_label( $parameter ) ),

		) );

		return false;
	}

	/**
	 * @inheritDoc
	 */
	public function get_hint( Parameter $parameter ): ?string {
		$config = $parameter->get_config();

		if ( empty( $config['options'] ) || ! is_array( $config['options'] ) ) {
			return null;
		}

		$options_list = implode( ', ',
			array_map(
				function ( $option ) {
					return $option['label'] ?? $option['value'] ?? 'unknown';
				},
				$config['options']
			) );

		return sprintf(
			__( 'Available options: %s', 'limb-chatbot' ),
			$options_list
		);
	}

	public function get_config_schema(): array {
		return array(
			'options' => array(
				'type'        => 'array',
				'description' => 'Button options',
				'required'    => true,
			),
			'is_multiselect' => array(
				'type'        => 'boolean',
				'description' => 'Allow multiple selections (comma-separated values)',
				'required'    => false,
			),
			'lead_capture_map_field' => array(
				'type'        => 'integer',
				'description' => 'Lead capture map field',
				'required'    => false,
			),
		);
	}
}

