<?php
/**
 * Action Execution Exception Class
 *
 * Exception for action execution failures.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Exceptions;

use Throwable;

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Class ActionException
 *
 * Thrown when a workflow action fails to execute.
 * Supports marking errors as retryable for transient failures.
 */
class ActionException extends SequensyException {

	/**
	 * Action type that failed.
	 *
	 * @var string
	 */
	protected string $action_type;

	/**
	 * Action index in the workflow.
	 *
	 * @var int|null
	 */
	protected ?int $action_index;

	/**
	 * Workflow ID.
	 *
	 * @var int|null
	 */
	protected ?int $workflow_id;

	/**
	 * Constructor.
	 *
	 * @param string         $message      Error message.
	 * @param string         $action_type  Action type that failed.
	 * @param bool           $retryable    Whether the error is retryable.
	 * @param array          $context      Additional context data.
	 * @param Throwable|null $previous     Previous exception.
	 */
	public function __construct(
		string $message = '',
		string $action_type = '',
		bool $retryable = false,
		array $context = array(),
		?Throwable $previous = null
	) {
		$this->action_type = $action_type;
		$this->retryable   = $retryable;

		// Extract workflow and action info from context.
		$this->workflow_id  = isset( $context['workflow_id'] ) ? (int) $context['workflow_id'] : null;
		$this->action_index = isset( $context['action_index'] ) ? (int) $context['action_index'] : null;

		// Ensure action type is in context.
		$context['action_type'] = $action_type;
		$context['retryable']   = $retryable;

		parent::__construct( $message, 0, $context, $previous );
	}

	/**
	 * Get the action type that failed.
	 *
	 * @return string Action type.
	 */
	public function get_action_type(): string {
		return $this->action_type;
	}

	/**
	 * Get the action index in the workflow.
	 *
	 * @return int|null Action index.
	 */
	public function get_action_index(): ?int {
		return $this->action_index;
	}

	/**
	 * Get workflow ID.
	 *
	 * @return int|null Workflow ID.
	 */
	public function get_workflow_id(): ?int {
		return $this->workflow_id;
	}

	/**
	 * Get the WP_Error code for this exception.
	 *
	 * @return string Error code.
	 */
	protected function get_error_code(): string {
		return 'sequensy_action_error';
	}

	/**
	 * Create a retryable action exception.
	 *
	 * @param string $message     Error message.
	 * @param string $action_type Action type.
	 * @param array  $context     Additional context.
	 * @return static Exception instance.
	 */
	public static function retryable( string $message, string $action_type, array $context = array() ): static {
		return new static( $message, $action_type, true, $context );
	}

	/**
	 * Create a non-retryable action exception.
	 *
	 * @param string $message     Error message.
	 * @param string $action_type Action type.
	 * @param array  $context     Additional context.
	 * @return static Exception instance.
	 */
	public static function fatal( string $message, string $action_type, array $context = array() ): static {
		return new static( $message, $action_type, false, $context );
	}
}
