<?php

namespace Limb_Chatbot\Includes\Services\Actions\Parameter_Types;

use Limb_Chatbot\Includes\Data_Objects\Parameter;

/**
 * Class Date_Parameter_Type
 *
 * Handles date parameter validation and sanitization.
 * Expects ISO format: YYYY-MM-DD (e.g., 2026-03-26).
 *
 * @package Limb_Chatbot\Includes\Services\Actions\Parameter_Types
 * @since 1.0.0
 */
class Date_Parameter_Type extends Abstract_Parameter_Type {

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

	/**
	 * @inheritDoc
	 */
	public function get_config_schema(): array {
		return [
			'min_date' => [
				'type'        => 'string',
				'description' => 'Minimum allowed date in YYYY-MM-DD format',
				'required'    => false,
			],
			'max_date' => [
				'type'        => 'string',
				'description' => 'Maximum allowed date in YYYY-MM-DD format',
				'required'    => false,
			],
			'lead_capture_map_field' => [
				'type'        => 'integer',
				'description' => 'Lead capture map field',
				'required'    => false,
			],
		];
	}

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

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

		$trimmed_value = trim( $value );
		if ( empty( $trimmed_value ) ) {
			if ( $this->is_required( $parameter ) ) {
				$this->add_error(
					sprintf(
						__( '%s is required.', 'limb-chatbot' ),
						$this->get_label( $parameter )
					)
				);

				return false;
			}

			return true;
		}

		if ( ! $this->is_valid_ymd( $trimmed_value ) ) {
			$this->add_error(
				sprintf(
					__( 'Please provide a valid date for %s in YYYY-MM-DD format.', 'limb-chatbot' ),
					$this->get_label( $parameter )
				)
			);

			return false;
		}

		$config = $parameter->get_config();
		if ( ! is_array( $config ) ) {
			return true;
		}

		$min_resolved = $this->resolve_config_date_bound( $config['min_date'] ?? null );
		$max_resolved = $this->resolve_config_date_bound( $config['max_date'] ?? null );

		if ( $min_resolved && $trimmed_value < $min_resolved ) {
			$this->add_error(
				sprintf(
					__( '%s must be on or after %s.', 'limb-chatbot' ),
					$this->get_label( $parameter ),
					$min_resolved
				)
			);

			return false;
		}

		if ( $max_resolved && $trimmed_value > $max_resolved ) {
			$this->add_error(
				sprintf(
					__( '%s must be on or before %s.', 'limb-chatbot' ),
					$this->get_label( $parameter ),
					$max_resolved
				)
			);

			return false;
		}

		return true;
	}

	/**
	 * @inheritDoc
	 */
	public function is_valid_config( string $config_key, $config_value ): bool {
		if ( in_array( $config_key, [ 'min_date', 'max_date' ], true ) ) {
			if ( null === $config_value || '' === $config_value ) {
				return true;
			}
			if ( is_string( $config_value ) && strtolower( $config_value ) === 'today' ) {
				return true;
			}

			return is_string( $config_value ) && $this->is_valid_ymd( $config_value );
		}

		return parent::is_valid_config( $config_key, $config_value );
	}

	/**
	 * Turn config bound (null, empty, "today", YYYY-MM-DD) into YYYY-MM-DD or null.
	 *
	 * @param  mixed  $raw  Config value.
	 * @return string|null Resolved YYYY-MM-DD or no bound.
	 */
	private function resolve_config_date_bound( $raw ): ?string {
		if ( null === $raw || '' === $raw ) {
			return null;
		}
		if ( ! is_string( $raw ) ) {
			return null;
		}
		if ( strtolower( $raw ) === 'today' ) {
			return function_exists( 'wp_date' ) ? wp_date( 'Y-m-d' ) : gmdate( 'Y-m-d' );
		}
		if ( $this->is_valid_ymd( $raw ) ) {
			return $raw;
		}

		return null;
	}

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

		return sprintf(
			__( 'For example: %s', 'limb-chatbot' ),
			$placeholder ?: '2026-03-26'
		);
	}

	/**
	 * Validate strict YYYY-MM-DD format and real calendar date.
	 *
	 * @param  string  $value
	 *
	 * @return bool
	 */
	private function is_valid_ymd( string $value ): bool {
		if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $value ) ) {
			return false;
		}

		$parts = explode( '-', $value );

		return checkdate( (int) $parts[1], (int) $parts[2], (int) $parts[0] );
	}
}

