<?php

namespace Limb_Chatbot\Includes\Services\Actions\Parameter_Types;

use Limb_Chatbot\Includes\Data_Objects\Parameter;

/**
 * Class Number_Parameter_Type
 *
 * Handles numeric parameter validation and sanitization.
 * Supports integer and decimal values.
 *
 * @package Limb_Chatbot\Includes\Services\Actions\Parameter_Types
 * @since 1.0.0
 */
class Number_Parameter_Type extends Abstract_Parameter_Type {

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

	/**
	 * @inheritDoc
	 */
	public function get_validation_rules_schema(): array {
		return [
			'min' => [
				'type'        => 'number',
				'description' => 'Minimum numeric value',
				'required'    => false,
			],
			'max' => [
				'type'        => 'number',
				'description' => 'Maximum numeric value',
				'required'    => false,
			],
			'step' => [
				'type'        => 'number',
				'description' => 'Allowed numeric increment',
				'required'    => false,
			],
			'integer_only' => [
				'type'        => 'boolean',
				'description' => 'Whether value must be an integer',
				'required'    => false,
			],
		];
	}

	/**
	 * @inheritDoc
	 */
	public function get_config_schema(): array {
		return [
			'lead_capture_map_field' => [
				'type'        => 'integer',
				'description' => 'Lead capture map field',
				'required'    => false,
			],
		];
	}

	/**
	 * @inheritDoc
	 */
	public function sanitize( string $value, Parameter $parameter ): string {
		$normalized = trim( str_replace( ',', '.', $value ) );
		if ( '' === $normalized ) {
			return '';
		}

		if ( ! is_numeric( $normalized ) ) {
			return sanitize_text_field( $normalized );
		}

		$number = (float) $normalized;
		$rules  = $parameter->get_validation_rules() ?: [];

		if ( ! empty( $rules['integer_only'] ) ) {
			return (string) (int) round( $number );
		}

		return $this->normalize_number_string( $number );
	}

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

		$normalized = trim( str_replace( ',', '.', $value ) );
		if ( '' === $normalized ) {
			if ( $this->is_required( $parameter ) ) {
				$this->add_error( sprintf( __( '%s is required.', 'limb-chatbot' ), $this->get_label( $parameter ) ) );
				return false;
			}

			return true;
		}

		if ( ! is_numeric( $normalized ) ) {
			$this->add_error( sprintf( __( 'Please provide a valid number for %s.', 'limb-chatbot' ), $this->get_label( $parameter ) ) );
			return false;
		}

		$number = (float) $normalized;
		$rules  = $parameter->get_validation_rules() ?: [];

		if ( ! empty( $rules['integer_only'] ) && floor( $number ) !== $number ) {
			$this->add_error( sprintf( __( '%s must be a whole number.', 'limb-chatbot' ), $this->get_label( $parameter ) ) );
			return false;
		}

		if ( isset( $rules['min'] ) && is_numeric( $rules['min'] ) && $number < (float) $rules['min'] ) {
			$this->add_error( sprintf( __( '%s must be greater than or equal to %s.', 'limb-chatbot' ), $this->get_label( $parameter ), $this->normalize_number_string( (float) $rules['min'] ) ) );
			return false;
		}

		if ( isset( $rules['max'] ) && is_numeric( $rules['max'] ) && $number > (float) $rules['max'] ) {
			$this->add_error( sprintf( __( '%s must be less than or equal to %s.', 'limb-chatbot' ), $this->get_label( $parameter ), $this->normalize_number_string( (float) $rules['max'] ) ) );
			return false;
		}

		if ( isset( $rules['step'] ) && is_numeric( $rules['step'] ) ) {
			$step = (float) $rules['step'];
			if ( $step > 0 ) {
				$base   = ( isset( $rules['min'] ) && is_numeric( $rules['min'] ) ) ? (float) $rules['min'] : 0.0;
				$delta  = ( $number - $base ) / $step;
				$close  = abs( $delta - round( $delta ) ) < 0.000001;
				if ( ! $close ) {
					$this->add_error( sprintf( __( '%s must follow step %s.', 'limb-chatbot' ), $this->get_label( $parameter ), $this->normalize_number_string( $step ) ) );
					return false;
				}
			}
		}

		return true;
	}

	/**
	 * @inheritDoc
	 */
	public function get_hint( Parameter $parameter ): ?string {
		$placeholder = $parameter->get_placeholder();
		return sprintf( __( 'For example: %s', 'limb-chatbot' ), $placeholder ?: '42' );
	}

	/**
	 * @inheritDoc
	 */
	public function is_valid_rule( string $rule_key, $rule_value ): bool {
		if ( null === $rule_value || '' === $rule_value ) {
			return true;
		}

		return parent::is_valid_rule( $rule_key, $rule_value );
	}

	/**
	 * Convert float to stable string without trailing zeros.
	 *
	 * @param  float  $number Numeric value.
	 * @return string
	 */
	private function normalize_number_string( float $number ): string {
		$formatted = number_format( $number, 10, '.', '' );
		$formatted = rtrim( rtrim( $formatted, '0' ), '.' );

		return '' === $formatted ? '0' : $formatted;
	}
}
