<?php
/**
 * Background tick job runner.
 *
 * @package Niwa_AI
 */

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

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

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

	public function run( $jobs, $debug_event = '' ) {
		$jobs   = is_array( $jobs ) ? $jobs : array();
		$errors = array();

		foreach ( $jobs as $name => $callback ) {
			if ( ! is_callable( $callback ) ) {
				continue;
			}

			try {
				$result = call_user_func( $callback );
				$errors = array_merge( $errors, $this->collect_job_errors( $name, $result ) );
			} catch ( Throwable $e ) {
				$errors[] = $name . ': ' . (string) $this->call( 'format_exception', array( $e ), $e->getMessage() );
			}
		}

		if ( '' !== trim( (string) $debug_event ) ) {
			$this->debug(
				$debug_event,
				array(
					'success' => empty( $errors ),
					'errors'  => array_slice( $errors, 0, 5 ),
				)
			);
		}

		return array(
			'success' => empty( $errors ),
			'errors'  => $errors,
		);
	}

	private function collect_job_errors( $name, $result ) {
		$name   = (string) $name;
		$result = is_array( $result ) ? $result : array();
		$errors = array();

		if ( ! empty( $result['error'] ) ) {
			$errors[] = $name . ': ' . (string) $result['error'];
		}
		if ( ! empty( $result['errors'] ) && is_array( $result['errors'] ) ) {
			foreach ( array_values( array_filter( $result['errors'] ) ) as $error ) {
				$errors[] = $name . ': ' . (string) $error;
			}
		}

		return $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 );
	}
}
