<?php
/**
 * Image ALT job manager.
 *
 * @package SmartyPress_AI_Engine
 */

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

/**
 * Stores lightweight bulk-generation queue state in options.
 */
class SmartyPress_AI_Image_ALT_Job_Manager {

	const OPTION_NAME = 'smartypress_ai_image_alt_job';

	/**
	 * Service.
	 *
	 * @var SmartyPress_AI_Image_ALT_Service
	 */
	private $service;

	/**
	 * Index manager.
	 *
	 * @var SmartyPress_AI_Image_ALT_Index_Manager
	 */
	private $index_manager;

	/**
	 * Constructor.
	 *
	 * @param SmartyPress_AI_Image_ALT_Service       $service       Service.
	 * @param SmartyPress_AI_Image_ALT_Index_Manager $index_manager Index manager.
	 */
	public function __construct( SmartyPress_AI_Image_ALT_Service $service, SmartyPress_AI_Image_ALT_Index_Manager $index_manager ) {
		$this->service       = $service;
		$this->index_manager = $index_manager;
	}

	/**
	 * Start a new bulk job.
	 *
	 * @param array $filters Query filters.
	 * @return array
	 */
	public function start( array $filters ) {
		if ( ! $this->index_manager->is_ready() ) {
			return array(
				'success' => false,
				'error'   => __( 'Image index is not ready. Please finish indexing before starting bulk generation.', 'smartypress-ai-engine' ),
			);
		}

		$total = $this->index_manager->count_for_generation( $filters );
		$job = array(
			'id'         => wp_generate_uuid4(),
			'status'     => 'running',
			'filters'    => $filters,
			'source'     => 'index',
			'last_id'    => 0,
			'total'      => $total,
			'processed'  => 0,
			'updated'    => 0,
			'skipped'    => 0,
			'failed'     => 0,
			'errors'     => array(),
			'started_at' => current_time( 'mysql' ),
			'updated_at' => current_time( 'mysql' ),
		);

		update_option( self::OPTION_NAME, $job, false );

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

	/**
	 * Process next chunk.
	 *
	 * @param SmartyPress_AI_AI_Provider|null $provider      Vision provider.
	 * @param array                          $settings      Settings.
	 * @param int                            $batch_size    Batch size.
	 * @param SmartyPress_AI_AI_Provider|null $text_provider Text provider.
	 * @return array
	 */
	public function process_next( $provider, array $settings, $batch_size = 1, $text_provider = null ) {
		$job = $this->get();
		if ( empty( $job ) || 'running' !== ( $job['status'] ?? '' ) ) {
			return array(
				'success' => false,
				'error'   => __( 'No running ALT generation job found.', 'smartypress-ai-engine' ),
			);
		}

		$batch_size = max( 1, min( 5, absint( $batch_size ) ) );
		$items      = $this->get_next_items( $job, $batch_size );
		$results    = array();

		if ( empty( $items ) ) {
			$job['status']      = 'completed';
			$job['finished_at'] = current_time( 'mysql' );
			$job['updated_at']  = current_time( 'mysql' );
			update_option( self::OPTION_NAME, $job, false );

			return array(
				'success' => true,
				'job'     => $job,
				'results' => $results,
			);
		}

		foreach ( $items as $attachment_id ) {
			$result = $this->service->generate_for_attachment( $attachment_id, $provider, $settings, $text_provider );
			$results[] = $result;
			$job['processed']++;
			$job['last_id'] = max( absint( $job['last_id'] ?? 0 ), absint( $attachment_id ) );

			if ( ! empty( $result['skipped'] ) ) {
				$job['skipped']++;
			} elseif ( ! empty( $result['success'] ) ) {
				$job['updated']++;
			} else {
				$job['failed']++;
				$job['errors'][] = array(
					'attachment_id' => $attachment_id,
					'error'         => $result['error'] ?? __( 'Unknown error', 'smartypress-ai-engine' ),
				);
				$job['errors'] = array_slice( $job['errors'], -20 );
			}
		}

		if ( $job['processed'] >= $job['total'] ) {
			$job['status']      = 'completed';
			$job['finished_at'] = current_time( 'mysql' );
		}

		$job['updated_at'] = current_time( 'mysql' );
		update_option( self::OPTION_NAME, $job, false );

		return array(
			'success' => true,
			'job'     => $job,
			'results' => $results,
		);
	}

	/**
	 * Cancel current job.
	 *
	 * @return array
	 */
	public function cancel() {
		$job = $this->get();
		if ( empty( $job ) ) {
			return array( 'status' => 'idle' );
		}

		$job['status']      = 'cancelled';
		$job['finished_at'] = current_time( 'mysql' );
		update_option( self::OPTION_NAME, $job, false );

		return $job;
	}

	/**
	 * Get current job.
	 *
	 * @return array
	 */
	public function get() {
		$job = get_option( self::OPTION_NAME, array() );
		return is_array( $job ) ? $job : array();
	}

	/**
	 * Get next job items.
	 *
	 * @param array $job        Job state.
	 * @param int   $batch_size Batch size.
	 * @return int[]
	 */
	private function get_next_items( array &$job, $batch_size ) {
		if ( 'index' === ( $job['source'] ?? '' ) ) {
			return $this->index_manager->query_generation_ids(
				$job['filters'] ?? array(),
				absint( $job['last_id'] ?? 0 ),
				$batch_size
			);
		}

		return array_splice( $job['queue'], 0, $batch_size );
	}
}
