<?php

namespace SugarCalendarBookings\Support\SmartTags;

use SugarCalendarBookings\Support\SmartTags\SmartTagInterface;

/**
 * Smart tag processor for processing smart tags in content.
 *
 * @since 1.0.0
 */
class SmartTagProcessor {

	/**
	 * Smart tags.
	 *
	 * @since 1.0.0
	 *
	 * @var SmartTagInterface[]
	 */
	private $smart_tags;

	/**
	 * Cache for processed smart tag values.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $cache = [];

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param SmartTagInterface[] $smart_tags Array of smart tag objects.
	 */
	public function __construct( $smart_tags = [] ) {

		$this->smart_tags = [];

		foreach ( $smart_tags as $smart_tag ) {
			if ( $smart_tag instanceof SmartTagInterface ) {
				$this->smart_tags[ $smart_tag->get_key() ] = $smart_tag;
			}
		}
	}

	/**
	 * Add a smart tag to the processor.
	 *
	 * @since 1.0.0
	 *
	 * @param SmartTagInterface $smart_tag Smart tag object.
	 *
	 * @return void
	 */
	public function add_smart_tag( $smart_tag ) {

		if ( $smart_tag instanceof SmartTagInterface ) {
			$this->smart_tags[ $smart_tag->get_key() ] = $smart_tag;
		}
	}

	/**
	 * Add multiple smart tags to the processor.
	 *
	 * @since 1.0.0
	 *
	 * @param SmartTagInterface[] $smart_tags Array of smart tag objects.
	 *
	 * @return void
	 */
	public function add_smart_tags( $smart_tags ) {

		foreach ( $smart_tags as $smart_tag ) {
			$this->add_smart_tag( $smart_tag );
		}
	}

	/**
	 * Process smart tags in the provided content.
	 *
	 * @since 1.0.0
	 *
	 * @param string $content Content to process smart tags in.
	 *
	 * @return string Processed content.
	 */
	public function process( $content ): string {

		// Pattern to match placeholders in format {key}.
		$pattern = '/\{([^}]+)\}/';

		return preg_replace_callback(
			$pattern,
			[ $this, 'replace_placeholder' ],
			$content
		);
	}

	/**
	 * Process placeholders with additional context (array data).
	 *
	 * @since 1.0.0
	 *
	 * @param string $content Content to process.
	 * @param array  $data    Additional data array to use for replacements.
	 *
	 * @return string Processed content.
	 */
	public function process_with_data( $content, $data = [] ): string {

		// First, process regular placeholders.
		$content = $this->process( $content );

		// Then, process additional data placeholders.
		if ( ! empty( $data ) ) {
			foreach ( $data as $key => $value ) {
				$content = str_replace( '{' . $key . '}', $value, $content );
			}
		}

		return $content;
	}

	/**
	 * Callback function for preg_replace_callback to replace a single placeholder.
	 *
	 * @since 1.0.0
	 *
	 * @param array $matches Matches from regex.
	 *
	 * @return string Replacement value.
	 */
	private function replace_placeholder( $matches ): string {

		$placeholder_key = '{' . $matches[1] . '}';

		// Check if value is cached.
		if ( isset( $this->cache[ $placeholder_key ] ) ) {
			return $this->cache[ $placeholder_key ];
		}

		// Get value from placeholder object and cache it.
		$value = '';

		if ( isset( $this->smart_tags[ $placeholder_key ] ) ) {
			$value = $this->smart_tags[ $placeholder_key ]->get_value();
		}

		$this->cache[ $placeholder_key ] = $value;

		return $value;
	}

	/**
	 * Clear cached values.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function clear_cache() {

		$this->cache = [];
	}

	/**
	 * Get all available placeholder keys.
	 *
	 * @since 1.0.0
	 *
	 * @return array Array of placeholder keys.
	 */
	public function get_placeholder_keys(): array {

		return array_keys( $this->smart_tags );
	}

	/**
	 * Check if a placeholder exists.
	 *
	 * @since 1.0.0
	 *
	 * @param string $key Placeholder key to check.
	 *
	 * @return bool True if placeholder exists, false otherwise.
	 */
	public function has_placeholder( $key ) {

		return isset( $this->smart_tags[ $key ] );
	}
}
