<?php

namespace VendorTasksDokanClickUp\Queue;

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

/**
 * Pending Task Queue
 *
 * Stores vendor IDs that failed task creation so they can be retried.
 * Uses a non-autoloaded WP option as a lightweight queue.
 *
 * @since 1.1.0
 * @package VendorTasksDokanClickUp
 * @subpackage Queue
 */
class PendingQueue {

	/**
	 * WP option name for the queue
	 *
	 * @var string
	 */
	private const OPTION_NAME = 'vendor_tasks_dokan_clickup_pending_queue';

	/**
	 * Add vendor ID to the queue
	 *
	 * @since 1.1.0
	 *
	 * @param int $vendor_id Vendor user ID.
	 * @return void
	 */
	public function enqueue( int $vendor_id ): void {
		$queue = $this->get_all();

		foreach ( $queue as $item ) {
			if ( (int) $item['vendor_id'] === $vendor_id ) {
				return; // Already queued
			}
		}

		$queue[] = array(
			'vendor_id' => $vendor_id,
			'attempts'  => 0,
			'queued_at' => time(),
		);

		update_option( self::OPTION_NAME, $queue, false );
	}

	/**
	 * Remove vendor ID from the queue
	 *
	 * @since 1.1.0
	 *
	 * @param int $vendor_id Vendor user ID.
	 * @return void
	 */
	public function dequeue( int $vendor_id ): void {
		$queue = array_values(
			array_filter(
				$this->get_all(),
				function ( $item ) use ( $vendor_id ) {
					return (int) $item['vendor_id'] !== $vendor_id;
				}
			)
		);

		update_option( self::OPTION_NAME, $queue, false );
	}

	/**
	 * Get all queued vendors
	 *
	 * @since 1.1.0
	 *
	 * @return array List of queue items: [ vendor_id, attempts, queued_at, last_attempt? ]
	 */
	public function get_all(): array {
		$queue = get_option( self::OPTION_NAME, array() );
		return is_array( $queue ) ? $queue : array();
	}

	/**
	 * Return up to $n items with the fewest retry attempts (FIFO within same count).
	 *
	 * @since 1.4.0
	 *
	 * @param int $n Maximum number of items to return.
	 * @return array<int, array{vendor_id: int, attempts: int, queued_at: int}> Subset of queue items.
	 */
	public function next_batch( int $n ): array {
		$queue = $this->get_all();

		usort(
			$queue,
			function ( array $a, array $b ): int {
				return ( (int) $a['attempts'] ) - ( (int) $b['attempts'] );
			}
		);

		return array_slice( $queue, 0, max( 1, $n ) );
	}

	/**
	 * Increment attempt count for a vendor and record timestamp
	 *
	 * @since 1.1.0
	 *
	 * @param int $vendor_id Vendor user ID.
	 * @return void
	 */
	public function increment_attempts( int $vendor_id ): void {
		$queue = $this->get_all();

		foreach ( $queue as &$item ) {
			if ( (int) $item['vendor_id'] === $vendor_id ) {
				++$item['attempts'];
				$item['last_attempt'] = time();
				break;
			}
		}
		unset( $item );

		update_option( self::OPTION_NAME, $queue, false );
	}

	/**
	 * Clear the entire queue
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function clear(): void {
		delete_option( self::OPTION_NAME );
	}
}
