<?php

namespace Limb_Chatbot\Includes\Services\Knowledge;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Dataset_Entry;
use Limb_Chatbot\Includes\Data_Objects\Message;

/**
 * Class Knowledge_Source_Tracker
 *
 * Tracks and manages dataset entry sources used in AI responses.
 * Stores source information as message metadata for accountability and validation.
 *
 * @package Limb_Chatbot\Includes\Services
 * @since 1.0.0
 */
class Knowledge_Source_Tracker {

	/**
	 * Meta key for storing dataset entry source IDs.
	 *
	 * @since 1.0.0
	 */
	const META_KEY_DATASET_ENTRY_SOURCES = 'dataset_entry_sources';

	/**
	 * Stores knowledge source information for an AI response message.
	 *
	 * @param  Message  $message  The AI response message.
	 * @param  array  $dataset_entries  Array of dataset entries used as sources.
	 *
	 * @return void
	 * @throws Exception If metadata storage fails.
	 * @since 1.0.0
	 */
	public function store_sources( Message $message, array $dataset_entries ): void {
		if ( empty( $dataset_entries ) ) {
			return;
		}

		// Sort dataset entries by similarity score and limit to top 3
		$sorted_entries = $this->sort_and_limit_entries( $dataset_entries );

		// Extract dataset entry IDs
		$source_ids = [];
		foreach ( $sorted_entries as $entry ) {
			if ( $entry instanceof Dataset_Entry && $entry->get_id() ) {
				$source_ids[] = [
					'id'         => $entry->get_id(),
					'similarity' => $entry->get_score(),
				];
			}
		}



		if ( ! empty( $source_ids ) ) {
			// Store source IDs as JSON in message metadata
			$message->update_meta(
				self::META_KEY_DATASET_ENTRY_SOURCES,
				wp_json_encode( $source_ids, JSON_UNESCAPED_UNICODE )
			);
		}
	}

	/**
	 * Sort dataset entries by similarity score and limit to top 3 most relevant.
	 *
	 * @param  array  $entries  Array of dataset entries with scores.
	 *
	 * @return array Array of top 3 dataset entries sorted by highest similarity score.
	 * @since 1.0.0
	 */
	private function sort_and_limit_entries( array $entries ): array {
		if ( empty( $entries ) ) {
			return $entries;
		}

		// Sort entries by similarity score in descending order (highest first)
		usort( $entries, function( $a, $b ) {
			$score_a = $a->get_score() ?? 0;
			$score_b = $b->get_score() ?? 0;
			
			// Sort in descending order (highest score first)
			return $score_b <=> $score_a;
		} );

		// Limit to top 3 most similar entries
		return array_slice( $entries, 0, 3 );
	}
}
