<?php

declare( strict_types=1 );

namespace Limb_Chatbot\Includes\Services\System_Message;

use Limb_Chatbot\Includes\Services\System_Message\Chunks\System_Message_Chunk;

/**
 * System Message Assembler
 *
 * Centralized orchestrator for building complete system messages from modular chunks.
 *
 * Features:
 * - Collects chunks from multiple sources (base, integrations, custom)
 * - Integrates integration-specific chunks based on active integrations
 * - Respects chunk priority ordering
 * - Conditionally includes chunks based on context/state
 * - Builds final message with consistent formatting
 * - Applies filters for extensibility
 *
 * Workflow:
 * 1. Register base chunks (Core_Rules, User_Information, Verified_Knowledge)
 * 2. Register integration-specific chunks (WooCommerce, etc.)
 * 3. Build final message with conditional logic and priority ordering
 *
 * @since 1.1.1
 */
class System_Message_Assembler {

	/**
	 * Registered chunks.
	 *
	 * @var System_Message_Chunk[]
	 */
	private array $chunks = [];

	/**
	 * Add multiple chunks at once.
	 *
	 * @param  System_Message_Chunk[]  $chunks  Array of chunks.
	 *
	 * @return self For chaining.
	 */
	public function add_chunks( array $chunks ): self {
		foreach ( $chunks as $chunk ) {
			if ( $chunk instanceof System_Message_Chunk ) {
				$this->add_chunk( $chunk );
			}
		}

		return $this;
	}

	/**
	 * Add a chunk to the assembler.
	 *
	 * @param  System_Message_Chunk  $chunk  The chunk to add.
	 *
	 * @return self For chaining.
	 */
	public function add_chunk( System_Message_Chunk $chunk ): self {
		$chunk_class = get_class( $chunk );
		$this->chunks[ $chunk_class ] = $chunk;

		return $this;
	}

	/**
	 * Remove a chunk by class name.
	 *
	 * @param  string  $class_name  Fully qualified class name.
	 *
	 * @return self For chaining.
	 */
	public function remove_chunk( string $class_name ): self {
		unset( $this->chunks[ $class_name ] );

		return $this;
	}

	/**
	 * Get all registered chunks.
	 *
	 * @return System_Message_Chunk[]
	 */
	public function get_chunks(): array {
		return $this->chunks;
	}

	/**
	 * Check if a chunk is registered by class name.
	 *
	 * @param  string  $class_name  Fully qualified class name.
	 *
	 * @return bool
	 */
	public function has_chunk( string $class_name ): bool {
		return isset( $this->chunks[ $class_name ] );
	}

	/**
	 * Build the final system message from registered chunks.
	 *
	 * Process:
	 * 1. Filter chunks for inclusion based on should_include()
	 * 2. Sort by priority (lower = earlier)
	 * 3. Render each chunk
	 * 4. Join with blank lines
	 * 5. Apply final filter
	 *
	 * @return string The complete system message.
	 */
	public function build(): string {
		// Filter chunks for inclusion
		$active_chunks = array_filter(
			$this->chunks,
			static function ( System_Message_Chunk $chunk ) {
				return $chunk->should_include();
			}
		);

		if ( empty( $active_chunks ) ) {
			return '';
		}

		// Sort by priority (lower priority value = render first)
		usort(
			$active_chunks,
			static function ( System_Message_Chunk $a, System_Message_Chunk $b ) {
				return $a->get_priority() <=> $b->get_priority();
			}
		);

		// Render each chunk
		$rendered = [];
		foreach ( $active_chunks as $chunk ) {
			$chunk_output = $chunk->render();
			if ( ! empty( $chunk_output ) ) {
				$rendered[] = $chunk_output;
			}
		}

		if ( empty( $rendered ) ) {
			return '';
		}

		$message = implode( "\n\n", $rendered );

		// Allow plugins/integrations to modify the final message
		return apply_filters( 'lbaic_system_message_assembled', $message );
	}

	/**
	 * Clear all registered chunks.
	 *
	 * @return self For chaining.
	 */
	public function reset(): self {
		$this->chunks = [];

		return $this;
	}
}
