<?php
/**
 * Telegram polling cycle orchestration.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Admin_Autonomy_Telegram_Poll_Runner {
	/** @var object|null */
	private $telegram;

	/** @var object|null */
	private $album_buffer;

	/** @var array<string,callable> */
	private $callbacks;

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

	public function run() {
		$telegram_enabled = $this->telegram && $this->telegram->is_enabled();

		$this->debug( 'poll_checkpoint', array( 'stage' => 'enter' ) );

		$handled      = 0;
		$ignored      = 0;
		$updates      = 0;
		$errors       = array();
		$note         = '';
		$actor_result = array(
			'success'            => true,
			'processed_sessions' => 0,
			'processed_messages' => 0,
			'pending'            => false,
			'errors'             => array(),
		);
		$batches      = array();

		if ( ! $telegram_enabled ) {
			$note = 'telegram_disabled';
		} elseif ( ! empty( $this->call( 'is_telegram_webhook_active', array(), false ) ) ) {
			$note = 'webhook_active';
			$this->debug( 'poll_checkpoint', array( 'stage' => 'webhook_active_skip' ) );
		} else {
			$has_poll_lock = ! empty( $this->call( 'acquire_lock', array( 'telegram_poll', 180 ), false ) );

			if ( ! $has_poll_lock ) {
				$note = 'poll_locked';
			} else {
				try {
					$poll = $this->telegram->poll_updates();
					if ( empty( $poll['success'] ) ) {
						$errors[] = isset( $poll['error'] ) ? (string) $poll['error'] : 'Telegram fallback polling failed.';
						$note     = 'poll_failed';
					} elseif ( ! empty( $poll['webhook_active'] ) ) {
						$note = 'webhook_active';
					} else {
						$batch_updates = isset( $poll['updates'] ) && is_array( $poll['updates'] ) ? $poll['updates'] : array();
						$batches[]     = $batch_updates;
						$updates      += count( $batch_updates );
					}
				} finally {
					$this->call( 'release_lock', array( 'telegram_poll' ) );
				}
			}
		}

		$process_combined = function ( $combined ) use ( &$handled, &$ignored, &$errors ) {
			if ( null === $combined ) {
				return;
			}
			if ( ! empty( $combined['is_text_fragment'] ) ) {
				$this->call( 'log_telegram_transport_buffer_event', array( 'telegram_text_buffer_flushed', $combined ) );
			} elseif ( ! empty( $combined['is_album'] ) ) {
				$this->call( 'log_telegram_transport_buffer_event', array( 'telegram_album_buffer_flushed', $combined ) );
			}
			$result = $this->call( 'handle_incoming_message', array( $combined, false ), array() );
			$this->count_message_result( $result, $handled, $ignored, $errors );
		};

		if ( $telegram_enabled ) {
			$this->flush_ready_buffers( $process_combined );
			$this->process_poll_batches( $batches, $handled, $ignored, $errors );
			$this->flush_ready_buffers( $process_combined );
		}

		$whatsapp_batch_result = $this->call( 'flush_whatsapp_text_batch', array(), array() );
		if ( is_array( $whatsapp_batch_result ) ) {
			$handled += intval( isset( $whatsapp_batch_result['processed'] ) ? $whatsapp_batch_result['processed'] : 0 );
			$this->collect_errors( $errors, $whatsapp_batch_result );
		}

		$this->debug( 'poll_checkpoint', array( 'stage' => 'before_actor_runtime' ) );
		$scheduled_result = $this->call( 'process_due_scheduled_jobs', array( 5 ), array() );
		$this->collect_errors( $errors, $scheduled_result );

		$actor_result = $this->call( 'process_actor_runtime', array( 3 ), $actor_result );
		$this->debug(
			'poll_checkpoint',
			array(
				'stage'              => 'after_actor_runtime',
				'processed_messages' => intval( isset( $actor_result['processed_messages'] ) ? $actor_result['processed_messages'] : 0 ),
				'pending'            => ! empty( $actor_result['pending'] ),
			)
		);
		$this->collect_errors( $errors, $actor_result );

		$result = array(
			'success'            => true,
			'updates'            => $updates,
			'handled'            => $handled,
			'ignored'            => $ignored,
			'actor_sessions'     => intval( isset( $actor_result['processed_sessions'] ) ? $actor_result['processed_sessions'] : 0 ),
			'actor_messages'     => intval( isset( $actor_result['processed_messages'] ) ? $actor_result['processed_messages'] : 0 ),
			'has_pending_actors' => ! empty( $actor_result['pending'] ),
			'errors'             => $errors,
		);
		if ( '' !== $note ) {
			$result['note'] = $note;
		}

		return $result;
	}

	private function process_poll_batches( $batches, &$handled, &$ignored, &$errors ) {
		foreach ( $batches as $batch_updates ) {
			foreach ( $batch_updates as $update ) {
				$message = $this->telegram->extract_message_payload( $update );

				if ( $this->album_buffer && ! empty( $message['success'] ) ) {
					if ( ! empty( $message['media_group_id'] ) ) {
						$this->album_buffer->buffer_album_part( $message );
						$this->call( 'log_telegram_transport_buffer_event', array( 'telegram_album_buffered', $message ) );
						if ( ! empty( $message['update_id'] ) ) {
							$this->telegram->remember_processed_update( $message['update_id'] );
						}
						$ignored++;
						continue;
					}

					if ( $this->album_buffer->buffer_text_fragment( $message ) ) {
						$this->call( 'log_telegram_transport_buffer_event', array( 'telegram_text_buffered', $message ) );
						if ( ! empty( $message['chat_id'] ) ) {
							$this->call( 'begin_typing_feedback', array( $message['chat_id'] ) );
						}
						if ( ! empty( $message['update_id'] ) ) {
							$this->telegram->remember_processed_update( $message['update_id'] );
						}
						$ignored++;
						continue;
					}
				}

				$result = $this->call( 'process_extracted_telegram_message', array( $message, false ), array() );
				$this->count_message_result( $result, $handled, $ignored, $errors );
			}
		}
	}

	private function flush_ready_buffers( $process_combined ) {
		if ( ! $this->album_buffer ) {
			return;
		}

		foreach ( $this->album_buffer->flush_ready_albums() as $combined ) {
			$process_combined( $combined );
		}
		foreach ( $this->album_buffer->flush_ready_text_fragments() as $combined ) {
			$process_combined( $combined );
		}
	}

	private function count_message_result( $result, &$handled, &$ignored, &$errors ) {
		$result = is_array( $result ) ? $result : array();
		if ( ! empty( $result['ignored'] ) ) {
			$ignored++;
			return;
		}
		if ( ! empty( $result['success'] ) ) {
			$handled++;
			return;
		}
		if ( ! empty( $result['error'] ) ) {
			$errors[] = (string) $result['error'];
		}
	}

	private function collect_errors( &$errors, $result ) {
		if ( ! is_array( $result ) ) {
			return;
		}
		if ( ! empty( $result['error'] ) ) {
			$errors[] = (string) $result['error'];
		}
		if ( ! empty( $result['errors'] ) && is_array( $result['errors'] ) ) {
			$errors = array_merge( $errors, array_values( array_filter( $result['errors'] ) ) );
		}
	}

	private function debug( $event, $context = array() ) {
		$this->call( 'debug_logger', array( $event, $context ) );
	}

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