<?php
/**
 * Queues channel messages into the session actor runtime.
 *
 * @package Niwa_AI
 */

defined( 'ABSPATH' ) || exit;

class Niwa_AI_Admin_Autonomy_Actor_Intake {

	private $transport;
	private $actor_runtime;
	private $callbacks;

	public function __construct( $transport = null, $actor_runtime = null, $callbacks = array() ) {
		$this->transport     = $transport;
		$this->actor_runtime = $actor_runtime;
		$this->callbacks     = is_array( $callbacks ) ? $callbacks : array();
	}

	public function enqueue( $message, $wake_runner = true, $callback_acknowledged = false ) {
		$message = is_array( $message ) ? $message : array();

		if ( ! $this->call( 'should_queue_message', array( $message ), true ) ) {
			$this->log_message_event( 'incoming_message_not_queueable', $message, array(
				'kind' => isset( $message['kind'] ) ? (string) $message['kind'] : '',
			) );
			$this->remember_processed_update( $message );

			return array(
				'success' => true,
				'ignored' => true,
			);
		}

		$actor_entry = $this->actor_runtime && method_exists( $this->actor_runtime, 'enqueue_message' )
			? (array) $this->actor_runtime->enqueue_message( $message, $callback_acknowledged )
			: array();

		if ( ! empty( $actor_entry['duplicate_existing'] ) ) {
			$this->remember_processed_update( $message );
			$this->log_message_event( 'incoming_message_duplicate_actor_ignored', $message, array(
				'actor_id' => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
			) );

			return array(
				'success'   => true,
				'queued'    => false,
				'duplicate' => true,
				'actor_id'  => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
			);
		}

		if ( ! empty( $actor_entry['cancelled_existing'] ) ) {
			$this->remember_processed_update( $message );
			$this->log_message_event( 'incoming_message_cancelled_existing_actor', $message, array(
				'session_id' => isset( $actor_entry['session_id'] ) ? (string) $actor_entry['session_id'] : '',
				'actor_id'   => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
			) );

			$runner_dispatch = array();
			if ( $wake_runner ) {
				$chat_id = isset( $message['chat_id'] ) ? (string) $message['chat_id'] : '';
				$this->call( 'begin_typing_feedback', array( $chat_id ), null );
				$runner_dispatch = (array) $this->call(
					'dispatch_runner',
					array( 'message', intval( $this->call( 'runner_liveness_ttl', array(), 0 ) ) ),
					array()
				);
			}

			return array(
				'success'         => true,
				'queued'          => true,
				'cancelled'       => true,
				'actor_id'        => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
				'runner_dispatch' => $runner_dispatch,
			);
		}

		if ( empty( $actor_entry['id'] ) ) {
			$this->log_message_event( 'incoming_message_enqueue_failed', $message );
			$this->release_processed_update_reservation( $message );
			error_log( '[Niwa AI Admin Runtime] Failed to enqueue incoming actor message.' );

			return array(
				'success' => false,
				'error'   => 'actor_enqueue_failed',
				'reply'   => '',
			);
		}

		$this->remember_processed_update( $message );
		$this->log_message_event( 'incoming_message_queued', $message, array(
			'actor_id'    => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
			'wake_runner' => (bool) $wake_runner,
		) );

		$runner_dispatch = array();
		if ( $wake_runner ) {
			$chat_id = isset( $message['chat_id'] ) ? (string) $message['chat_id'] : '';
			$this->call( 'begin_typing_feedback', array( $chat_id ), null );
			$runner_dispatch = (array) $this->call(
				'dispatch_runner',
				array( 'message', intval( $this->call( 'runner_liveness_ttl', array(), 0 ) ) ),
				array()
			);
		}

		return array(
			'success'         => true,
			'queued'          => true,
			'actor_id'        => isset( $actor_entry['id'] ) ? (string) $actor_entry['id'] : '',
			'runner_dispatch' => $runner_dispatch,
		);
	}

	private function remember_processed_update( $message ) {
		$update_id = isset( $message['update_id'] ) ? intval( $message['update_id'] ) : 0;
		if ( $update_id > 0 && $this->transport && method_exists( $this->transport, 'remember_processed_update' ) ) {
			$this->transport->remember_processed_update( $update_id );
		}
	}

	private function release_processed_update_reservation( $message ) {
		$update_id = isset( $message['update_id'] ) ? intval( $message['update_id'] ) : 0;
		if ( $update_id > 0 && $this->transport && method_exists( $this->transport, 'release_processed_update_reservation' ) ) {
			$this->transport->release_processed_update_reservation( $update_id );
		}
	}

	private function log_message_event( $event, $message, $extra = array() ) {
		$context = array(
			'chat_id'    => isset( $message['chat_id'] ) ? (string) $message['chat_id'] : '',
			'message_id' => isset( $message['message_id'] ) ? intval( $message['message_id'] ) : 0,
			'update_id'  => isset( $message['update_id'] ) ? intval( $message['update_id'] ) : 0,
			'channel'    => isset( $message['channel'] ) ? sanitize_key( (string) $message['channel'] ) : '',
		);

		$this->call( 'debug_logger', array( $event, array_merge( $context, is_array( $extra ) ? $extra : array() ) ), null );
	}

	private function call( $name, $args = array(), $default = null ) {
		return Niwa_AI_Admin_Autonomy_Callbacks::call( $this->callbacks, $name, $args, $default );
	}
}
