<?php
/**
 * Actor runtime lease and heartbeat refresh helper.
 *
 * @package Niwa_AI
 */

defined( 'ABSPATH' ) || exit;

class Niwa_AI_Admin_Autonomy_Actor_Runtime_Lease_Keeper {
	/** @var object|null */
	private $control_plane;

	/** @var int */
	private $base_lease_ttl;

	/** @var int */
	private $heartbeat_interval;

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

	public function __construct( $control_plane = null, $base_lease_ttl = 600, $heartbeat_interval = 30, $callbacks = array() ) {
		$this->control_plane      = $control_plane;
		$this->base_lease_ttl     = max( 60, intval( $base_lease_ttl ) );
		$this->heartbeat_interval = max( 1, intval( $heartbeat_interval ) );
		$this->callbacks          = is_array( $callbacks ) ? $callbacks : array();
	}

	public function set_control_plane( $control_plane ) {
		$this->control_plane = $control_plane;
	}

	public function get_lease_ttl() {
		$worker_limit = intval( $this->call( 'turn_worker_time_limit', array(), 0 ) );
		return max( $this->base_lease_ttl, $worker_limit + 120 );
	}

	public function refresh_message_lease( $session_id, $message_id ) {
		if ( ! $this->control_plane || ! method_exists( $this->control_plane, 'refresh_actor_message_lease' ) ) {
			return false;
		}

		$lease_ttl = $this->get_lease_ttl();
		$refreshed = ! empty(
			$this->control_plane->refresh_actor_message_lease(
				$session_id,
				$message_id,
				$lease_ttl
			)
		);

		if ( $refreshed ) {
			$this->refresh_runtime_locks( $session_id, $lease_ttl );
		}

		return $refreshed;
	}

	public function refresh_runtime_locks( $session_id, $ttl = null ) {
		if ( ! $this->control_plane || ! method_exists( $this->control_plane, 'refresh_session_lane' ) ) {
			return;
		}

		$session_id = trim( (string) $session_id );
		if ( '' === $session_id ) {
			return;
		}

		$ttl = null === $ttl ? $this->get_lease_ttl() : max( 60, intval( $ttl ) );
		$this->control_plane->refresh_session_lane( $session_id, $ttl );
		$this->control_plane->refresh_session_lane( 'actor-run:' . $session_id, $ttl );
	}

	public function wrap_message_lease_callback( $session_id, $message_id, $progress_callback ) {
		$session_id      = trim( (string) $session_id );
		$message_id      = trim( (string) $message_id );
		$last_refresh_at = 0;

		if ( '' === $session_id || '' === $message_id ) {
			return is_callable( $progress_callback ) ? $progress_callback : null;
		}

		return function ( $event = '', $payload = array() ) use ( $session_id, $message_id, $progress_callback, &$last_refresh_at ) {
			$now = time();
			if ( $now - $last_refresh_at >= $this->heartbeat_interval ) {
				$last_refresh_at = $now;
				$this->refresh_message_lease( $session_id, $message_id );
				$this->call( 'refresh_current_loopback_runner_liveness', array( $this->get_lease_ttl() ) );
			}

			if ( is_callable( $progress_callback ) ) {
				call_user_func( $progress_callback, $event, is_array( $payload ) ? $payload : array() );
			}
		};
	}

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