<?php

declare(strict_types=1);

/**
 * CloudUploadPhaseService - Hashing, cloud hash check, and upload phases.
 *
 * Consolidates the three tightly coupled RR phases (hash, cloud_check, upload)
 * into a single service. Internally round-robins between them using the same
 * logic as the original orchestrator. Delegates tick execution via callables
 * so all complex phase logic remains in ScanOrchestrator during this initial
 * extraction. A future refactoring can migrate that logic here directly.
 *
 */

namespace SecurWP\Modules\Scanner\Queue\Phase;

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

class CloudUploadPhaseService implements PhaseServiceInterface {

    private const SUB_PHASES = [ 'hash', 'cloud_check', 'upload' ];

    /** @var callable(array): bool */
    private $hash_tick_fn;

    /** @var callable(array): bool */
    private $cloud_check_tick_fn;

    /** @var callable(array): bool */
    private $upload_tick_fn;

    /** @var callable(): bool */
    private $is_complete_fn;

    /** @var string Current sub-phase for internal RR */
    private string $current_sub_phase = 'hash';

    /**
     * @param callable(array &$stats): bool $hash_tick_fn        Runs one hashing batch.
     * @param callable(array &$stats): bool $cloud_check_tick_fn Runs one cloud hash-check batch.
     * @param callable(array &$stats): bool $upload_tick_fn      Runs one upload batch.
     * @param callable(): bool              $is_complete_fn       True when hashing+upload pipeline is done.
     */
    public function __construct(
        callable $hash_tick_fn,
        callable $cloud_check_tick_fn,
        callable $upload_tick_fn,
        callable $is_complete_fn
    ) {
        $this->hash_tick_fn        = $hash_tick_fn;
        $this->cloud_check_tick_fn = $cloud_check_tick_fn;
        $this->upload_tick_fn      = $upload_tick_fn;
        $this->is_complete_fn      = $is_complete_fn;
    }

    public function tick( array &$stats ): bool {
        // Internal RR: try each sub-phase once per outer tick.
        $sub = $this->current_sub_phase;
        for ( $attempt = 0; $attempt < count( self::SUB_PHASES ); $attempt++ ) {
            switch ( $sub ) {
                case 'hash':
                    $did_work = ( $this->hash_tick_fn )( $stats );
                    break;
                case 'cloud_check':
                    $did_work = ( $this->cloud_check_tick_fn )( $stats );
                    break;
                case 'upload':
                    $did_work = ( $this->upload_tick_fn )( $stats );
                    break;
                default:
                    $did_work = false;
                    break;
            }
            $sub = $this->advance_sub_phase( $sub );
            if ( $did_work ) {
                $this->current_sub_phase = $sub;
                return true;
            }
        }
        $this->current_sub_phase = $sub;
        return false;
    }

    public function is_complete(): bool {
        return ( $this->is_complete_fn )();
    }

    public function get_phase_name(): string {
        return 'cloud_upload';
    }

    private function advance_sub_phase( string $current ): string {
        $idx = array_search( $current, self::SUB_PHASES, true );
        if ( $idx === false ) {
            return self::SUB_PHASES[0];
        }
        return self::SUB_PHASES[ ( $idx + 1 ) % count( self::SUB_PHASES ) ];
    }
}
