<?php
/**
 * Cart Recovery — Transcript Digester
 *
 * Given a chat session id, pulls the visitor's recent conversation
 * from `Niwa_AI_Conversation_Store` and turns it into a compact plain
 * text excerpt that fits cleanly into the composer prompt.
 *
 * Principles:
 *   - Chronological (oldest first among the last N kept).
 *   - Only user + assistant/bot messages. System / tool messages are
 *     noise for the mailer persona.
 *   - Hard per-line truncation so a single runaway message can't
 *     monopolize the excerpt budget.
 *   - Overall length capped — keeps prompt tokens bounded.
 *   - Graceful null store → empty string (composer then renders a
 *     "(no conversation excerpt)" sentinel path).
 *
 * @package Niwa_AI
 * @since   0.12.0
 */

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

class Niwa_AI_Cart_Recovery_Transcript_Digester {

	public function __construct(
		private readonly ?Niwa_AI_Conversation_Store $store = null
	) {}

	/**
	 * Produce a compact plain-text transcript for this session.
	 *
	 * @return string UTF-8, newline-separated, max CART_RECOVERY_TRANSCRIPT_MAX_CHARS.
	 */
	public function digest( string $session_id ): string {
		$session_id = trim( $session_id );
		if ( '' === $session_id || ! $this->store ) {
			return '';
		}

		$messages = $this->store->get( $session_id );
		if ( ! is_array( $messages ) || empty( $messages ) ) {
			return '';
		}

		$max_msgs   = (int) apply_filters( 'niwa_ai_cart_recovery_transcript_max_msgs', Niwa_AI_Constants::CART_RECOVERY_TRANSCRIPT_MAX_MSGS );
		$line_max   = (int) apply_filters( 'niwa_ai_cart_recovery_transcript_line_max', Niwa_AI_Constants::CART_RECOVERY_TRANSCRIPT_LINE_MAX );
		$total_max  = (int) apply_filters( 'niwa_ai_cart_recovery_transcript_max_chars', Niwa_AI_Constants::CART_RECOVERY_TRANSCRIPT_MAX_CHARS );

		$max_msgs  = max( 1, $max_msgs );
		$line_max  = max( 50, $line_max );
		$total_max = max( 100, $total_max );

		$slice = array_slice( $messages, -$max_msgs );
		$lines = array();

		foreach ( $slice as $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}

			$role = strtolower( (string) ( $item['role'] ?? '' ) );
			if ( ! in_array( $role, array( 'user', 'bot', 'assistant' ), true ) ) {
				continue;
			}

			// Conversation_Store uses `text`; fall back to `content` for robustness.
			$content = '';
			if ( isset( $item['text'] ) && is_string( $item['text'] ) ) {
				$content = $item['text'];
			} elseif ( isset( $item['content'] ) && is_string( $item['content'] ) ) {
				$content = $item['content'];
			}

			$content = trim( $this->collapse_whitespace( $content ) );
			if ( '' === $content ) {
				continue;
			}

			if ( mb_strlen( $content ) > $line_max ) {
				$content = mb_substr( $content, 0, $line_max - 1 ) . '…';
			}

			$label   = ( 'user' === $role ) ? 'KUPAC' : 'NIVA';
			$lines[] = $label . ': ' . $content;
		}

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

		$joined = implode( "\n", $lines );
		if ( mb_strlen( $joined ) > $total_max ) {
			$joined = mb_substr( $joined, -$total_max );
		}

		return $joined;
	}

	private function collapse_whitespace( string $text ): string {
		$text = str_replace( array( "\r\n", "\r" ), "\n", $text );
		$text = preg_replace( '/[ \t]+/', ' ', $text );
		$text = preg_replace( '/\n{3,}/', "\n\n", $text ?? '' );
		return is_string( $text ) ? $text : '';
	}
}
