<?php
/**
 * Truebe validator: catches seed collisions before a seed goes live.
 *
 * Enforces the seed contract at publish time. A seed that scores too close to an existing
 * ready seed would let the matcher pick the wrong one, so it is flagged here and the owner
 * is told which seed it overlaps, in plain language.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( class_exists( 'Truebe_Validator' ) ) {
	return;
}

class Truebe_Validator {

	/** Overlap at or above this share of shared distinctive tokens is a collision. */
	const OVERLAP_RATIO = 0.6;

	/**
	 * Check one seed against the current ready library.
	 *
	 * @param array $seed The pending seed (label, intent, keywords, phrasings).
	 * @return array { clear:bool, conflict_label:string, reason:string }
	 */
	public static function check( $seed ) {
		$mine = self::distinctive_tokens( $seed );
		if ( empty( $mine ) ) {
			return self::result( false, '', __( 'This answer has no distinctive wording to tell it apart from others. Edit it to be more specific.', 'truebe-fact-based-ai-chatbot' ) );
		}

		$ready = class_exists( 'Truebe_Seeds' ) ? Truebe_Seeds::get_ready_seeds() : array();
		foreach ( $ready as $other ) {
			if ( isset( $seed['id'], $other['id'] ) && (int) $seed['id'] === (int) $other['id'] ) {
				continue;
			}
			$theirs = self::distinctive_tokens( $other );
			if ( empty( $theirs ) ) {
				continue;
			}

			$shared = array_intersect_key( $mine, $theirs );
			$ratio  = count( $shared ) / max( count( $mine ), count( $theirs ) );

			$same_intent = self::intent_of( $seed ) === self::intent_of( $other );

			if ( $ratio >= self::OVERLAP_RATIO && $same_intent ) {
				return self::result(
					false,
					isset( $other['label'] ) ? (string) $other['label'] : '',
					__( 'This is too similar to another published answer. Make one of them more specific before publishing.', 'truebe-fact-based-ai-chatbot' )
				);
			}
		}

		return self::result( true, '', '' );
	}

	/**
	 * Distinctive token set for a seed: meaningful words from label, phrasings, keywords.
	 *
	 * @param array $seed
	 * @return array Set keyed by token.
	 */
	private static function distinctive_tokens( $seed ) {
		$texts = array( isset( $seed['label'] ) ? $seed['label'] : '' );
		if ( ! empty( $seed['phrasings'] ) && is_array( $seed['phrasings'] ) ) {
			$texts = array_merge( $texts, $seed['phrasings'] );
		}
		if ( ! empty( $seed['keywords'] ) && is_array( $seed['keywords'] ) ) {
			$texts = array_merge( $texts, $seed['keywords'] );
		}

		$set = array();
		foreach ( $texts as $text ) {
			$clean = trim( preg_replace( '/[^a-z0-9]+/', ' ', strtolower( (string) $text ) ) );
			if ( '' === $clean ) {
				continue;
			}
			foreach ( preg_split( '/\s+/', $clean, -1, PREG_SPLIT_NO_EMPTY ) as $tok ) {
				if ( strlen( $tok ) >= 4 ) {
					$set[ $tok ] = true;
				}
			}
		}
		return $set;
	}

	private static function intent_of( $seed ) {
		return isset( $seed['intent'] ) ? strtolower( trim( (string) $seed['intent'] ) ) : '';
	}

	private static function result( $clear, $conflict_label, $reason ) {
		return array(
			'clear'          => (bool) $clear,
			'conflict_label' => (string) $conflict_label,
			'reason'         => (string) $reason,
		);
	}
}