<?php

namespace Limb_Chatbot\Includes\Services\Jobs\Managers;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Job;
use Limb_Chatbot\Includes\Data_Objects\Task;
use Limb_Chatbot\Includes\Factories\Job_Handler_Factory;
use Limb_Chatbot\Includes\Interfaces\Multitask_Handler_Interface;
use Limb_Chatbot\Includes\Repositories\Job_Task_Repository;

/**
 * Job State Manager
 *
 * Handles job state transitions and completion checking.
 *
 * @since 1.1.0
 */
class Job_State_Manager {

	/**
	 * Task repository instance.
	 *
	 * @var Job_Task_Repository
	 * @since 1.1.0
	 */
	private Job_Task_Repository $task_repository;

	/**
	 * Constructor.
	 *
	 * @param  Job_Task_Repository  $task_repository  Task repository.
	 *
	 * @since 1.1.0
	 */
	public function __construct( Job_Task_Repository $task_repository ) {
		$this->task_repository = $task_repository;
	}

	/**
	 * Start processing a job.
	 *
	 * Transitions job to processing status if needed.
	 *
	 * @param  Job  $job  Job to start.
	 *
	 * @return void
	 * @throws Exception
	 * @since 1.1.0
	 */
	public function start_processing( Job $job ): void {
		if ( $job->is_processing() ) {
			return;
		}

		$job->set_status( Job::STATUS_PROCESSING );
		if ( ! $job->get_started_at() ) {
			$job->set_started_at( current_time( 'mysql', true ) );
		}
		$job->save();
	}

	/**
	 * Check if job is complete and update status accordingly.
	 *
	 * Also triggers job-specific completion handlers if needed.
	 *
	 * @param  Job  $job  Job to check.
	 *
	 * @return Job|null Returns the completed job if it was completed, null otherwise.
	 * @throws Exception
	 * @since 1.1.0
	 */
	public function check_and_complete( Job $job ) {
		// Check if job is in processing status
		if ( ! $job->is_processing() ) {
			return null;
		}

		// Determine if this is a multitask handler
		$factory = new Job_Handler_Factory();
		$handler = $factory->make( $job->get_type() );
		$is_multitask = $handler instanceof Multitask_Handler_Interface;

		if ( $is_multitask ) {
			// For multitask handlers, check child tasks only
			// Parent tasks can be in STATUS_CHILD_TASK_PENDING which is fine
			$child_task_counts = $this->task_repository->get_child_task_counts_by_status( $job->get_id() );
			
			$pending_child_tasks = $child_task_counts['pending'] ?? 0;
			$processing_child_tasks = $child_task_counts['processing'] ?? 0;
			
			// Job is complete if there are no pending or processing child tasks
			if ( $pending_child_tasks === 0 && $processing_child_tasks === 0 ) {
				return $this->mark_job_completed( $job, $handler );
			}
		} else {
			// For regular handlers, check all tasks
			$pending_count = $this->task_repository->count_by_status( $job->get_id(), Task::STATUS_PENDING );
			$processing_count = $this->task_repository->count_by_status( $job->get_id(), Task::STATUS_PROCESSING );
			
			// Job is complete if there are no pending or processing tasks
			if ( $pending_count === 0 && $processing_count === 0 ) {
				return $this->mark_job_completed( $job, $handler );
			}
		}
		
		return null;
	}

	/**
	 * Mark job as completed and trigger completion handlers.
	 *
	 * @param  Job  $job  Job to mark as completed.
	 * @param  mixed  $handler  Job handler instance.
	 *
	 * @return Job Completed job instance.
	 * @throws Exception
	 * @since 1.1.0
	 */
	private function mark_job_completed( Job $job, $handler ): Job {
		$job->set_status( Job::STATUS_COMPLETED );
		$job->set_progress_percent( 100.0 );
		$job->set_completed_at( current_time( 'mysql', true ) );
		$job->save();

		// Trigger job-specific completion handlers
		if ( method_exists( $handler, 'complete' ) ) {
			$handler->complete( $job );
		}
		
		return $job;
	}
}
