<?php
/**
 * Workflow REST API Controller
 *
 * Provides REST API endpoints for workflow CRUD operations.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Rest;

use Sequensy\Container;
use Sequensy\Storage\WorkflowStorage;
use Sequensy\Triggers\TriggerRegistry;
use Sequensy\Actions\ActionRegistry;
use Sequensy\Validation\WorkflowValidator;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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

/**
 * Class WorkflowController
 *
 * REST API controller for workflow CRUD operations.
 */
class WorkflowController extends WP_REST_Controller {

	use RestControllerTrait;

	/**
	 * Workflow storage instance.
	 *
	 * @var WorkflowStorage
	 */
	private WorkflowStorage $storage;

	/**
	 * Trigger registry instance.
	 *
	 * @var TriggerRegistry
	 */
	private TriggerRegistry $trigger_registry;

	/**
	 * Action registry instance.
	 *
	 * @var ActionRegistry
	 */
	private ActionRegistry $action_registry;

	/**
	 * Factory method for creating controller instance with container.
	 *
	 * @param Container $container Service container instance.
	 * @return self Controller instance.
	 */
	public static function create( Container $container ): self {
		return new self(
			$container->get( 'workflow_storage' ),
			$container->get( 'trigger_registry' ),
			$container->get( 'action_registry' )
		);
	}

	/**
	 * Constructor.
	 *
	 * @param WorkflowStorage|null $storage          Optional storage instance.
	 * @param TriggerRegistry|null $trigger_registry Optional trigger registry.
	 * @param ActionRegistry|null  $action_registry  Optional action registry.
	 */
	public function __construct(
		?WorkflowStorage $storage = null,
		?TriggerRegistry $trigger_registry = null,
		?ActionRegistry $action_registry = null
	) {
		$this->namespace = 'sequensy/v1';
		$this->rest_base = 'workflows';

		// Use provided dependencies or get from container.
		$container              = Container::getInstance();
		$this->storage          = $storage ?? $container->get( 'workflow_storage' );
		$this->trigger_registry = $trigger_registry ?? $container->get( 'trigger_registry' );
		$this->action_registry  = $action_registry ?? $container->get( 'action_registry' );
	}

	/**
	 * Register REST API routes.
	 */
	public function register_routes(): void {
		// List workflows.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_items' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => $this->get_collection_params(),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_item' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => $this->get_create_params(),
				),
			)
		);

		// Get, update, delete single workflow.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_item' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => array(
						'id' => array(
							'description'       => 'Workflow ID',
							'type'              => 'integer',
							'required'          => true,
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
						),
					),
				),
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_item' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => $this->get_update_params(),
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_item' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => array(
						'id' => array(
							'description'       => 'Workflow ID',
							'type'              => 'integer',
							'required'          => true,
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
						),
					),
				),
			)
		);
	}

	/**
	 * Get workflows.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object.
	 */
	public function get_items( $request ): WP_REST_Response|WP_Error {
		$filters = array();

		if ( ! empty( $request['status'] ) ) {
			$filters['status'] = sanitize_text_field( $request['status'] );
		}

		if ( ! empty( $request['trigger_type'] ) ) {
			$filters['trigger_type'] = sanitize_text_field( $request['trigger_type'] );
		}

		$per_page = ! empty( $request['per_page'] ) ? (int) $request['per_page'] : 20;
		$page     = ! empty( $request['page'] ) ? (int) $request['page'] : 1;
		$offset   = ( $page - 1 ) * $per_page;

		$workflows = $this->storage->get_workflows( $filters, $per_page, $offset );
		$total     = $this->storage->get_workflows_count( $filters );

		$response = rest_ensure_response( $workflows );
		$response->header( 'X-WP-Total', (string) $total );
		$response->header( 'X-WP-TotalPages', (string) ceil( $total / $per_page ) );

		return $response;
	}

	/**
	 * Create a workflow.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object.
	 */
	public function create_item( $request ): WP_REST_Response|WP_Error {
		/**
		 * Filter whether the current user can create a workflow.
		 *
		 * @param bool $can_create Whether creation is allowed. Default true.
		 */
		$can_create = apply_filters( 'sequensy_can_create_workflow', true );

		if ( ! $can_create ) {
			return $this->rest_error(
				'creation_blocked',
				__( 'Workflow creation is not available.', 'sequensy' ),
				403
			);
		}

		$data = array(
			'name'         => sanitize_text_field( $request['name'] ?? '' ),
			'description'  => sanitize_textarea_field( $request['description'] ?? '' ),
			'trigger_type' => sanitize_text_field( $request['trigger_type'] ?? '' ),
			'config'       => $request['config'] ?? array(),
			'status'       => 'inactive',
		);

		$workflow_id = $this->storage->create_workflow( $data );

		if ( ! $workflow_id ) {
			return $this->rest_error(
				'save_failed',
				__( 'Failed to save workflow', 'sequensy' ),
				500
			);
		}

		$workflow = $this->storage->get_workflow( $workflow_id );

		return rest_ensure_response( $workflow );
	}

	/**
	 * Get a single workflow.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object.
	 */
	public function get_item( $request ): WP_REST_Response|WP_Error {
		$workflow_id = (int) $request['id'];
		$workflow    = $this->storage->get_workflow( $workflow_id );

		if ( ! $workflow ) {
			return $this->rest_error(
				'not_found',
				__( 'Workflow not found', 'sequensy' ),
				404
			);
		}

		// Add version status to response for frontend draft badge.
		$workflow->has_unpublished_changes = $this->storage->has_unpublished_changes( $workflow_id );

		return rest_ensure_response( $workflow );
	}

	/**
	 * Update a workflow.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object.
	 */
	public function update_item( $request ): WP_REST_Response|WP_Error {
		$workflow = $this->storage->get_workflow( (int) $request['id'] );

		if ( ! $workflow ) {
			return $this->rest_error(
				'not_found',
				__( 'Workflow not found', 'sequensy' ),
				404
			);
		}

		$data = array(
			'id' => (int) $request['id'],
		);

		if ( isset( $request['name'] ) ) {
			$data['name'] = sanitize_text_field( $request['name'] );
		}

		if ( isset( $request['config'] ) ) {
			$data['config'] = $request['config'];
		}

		if ( isset( $request['status'] ) ) {
			$data['status'] = sanitize_text_field( $request['status'] );
		}

		// If activating, run full validation.
		if ( isset( $data['status'] ) && 'active' === $data['status'] ) {
			$merged_workflow = array_merge(
				(array) $workflow,
				$data
			);
			$validator       = new WorkflowValidator( $this->trigger_registry, $this->action_registry );
			$validation      = $validator->validate_for_activation( $merged_workflow );

			if ( ! $validation['valid'] ) {
				return $this->rest_error(
					'validation_failed',
					__( 'Workflow cannot be activated due to configuration errors.', 'sequensy' ),
					400,
					array( 'errors' => $validation['errors'] )
				);
			}
		}

		$result = $this->storage->update_workflow( (int) $request['id'], $data );

		if ( ! $result ) {
			return $this->rest_error(
				'update_failed',
				__( 'Failed to update workflow', 'sequensy' ),
				500
			);
		}

		$workflow = $this->storage->get_workflow( (int) $request['id'] );

		return rest_ensure_response( $workflow );
	}

	/**
	 * Delete a workflow.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error Response object.
	 */
	public function delete_item( $request ): WP_REST_Response|WP_Error {
		$workflow = $this->storage->get_workflow( (int) $request['id'] );

		if ( ! $workflow ) {
			return $this->rest_error(
				'not_found',
				__( 'Workflow not found', 'sequensy' ),
				404
			);
		}

		$result = $this->storage->delete_workflow( (int) $request['id'] );

		if ( ! $result ) {
			return $this->rest_error(
				'delete_failed',
				__( 'Failed to delete workflow', 'sequensy' ),
				500
			);
		}

		return rest_ensure_response(
			array(
				'deleted' => true,
				'id'      => (int) $request['id'],
			)
		);
	}

	/**
	 * Get collection parameters.
	 *
	 * @return array
	 */
	public function get_collection_params(): array {
		return array(
			'page'         => array(
				'description'       => 'Current page',
				'type'              => 'integer',
				'default'           => 1,
				'sanitize_callback' => 'absint',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'per_page'     => array(
				'description'       => 'Items per page',
				'type'              => 'integer',
				'default'           => 20,
				'sanitize_callback' => 'absint',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'status'       => array(
				'description'       => 'Filter by status',
				'type'              => 'string',
				'enum'              => array( 'active', 'inactive' ),
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'trigger_type' => array(
				'description'       => 'Filter by trigger type',
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
		);
	}

	/**
	 * Get create parameters.
	 *
	 * @return array
	 */
	public function get_create_params(): array {
		return array(
			'name'    => array(
				'description'       => 'Workflow name',
				'type'              => 'string',
				'required'          => true,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'trigger' => array(
				'description'       => 'Trigger configuration',
				'type'              => 'object',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'actions' => array(
				'description'       => 'Actions configuration',
				'type'              => 'array',
				'validate_callback' => 'rest_validate_request_arg',
			),
		);
	}

	/**
	 * Get update parameters.
	 *
	 * @return array
	 */
	public function get_update_params(): array {
		return array(
			'name'    => array(
				'description'       => 'Workflow name',
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'trigger' => array(
				'description'       => 'Trigger configuration',
				'type'              => 'object',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'actions' => array(
				'description'       => 'Actions configuration',
				'type'              => 'array',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'status'  => array(
				'description'       => 'Workflow status',
				'type'              => 'string',
				'enum'              => array( 'active', 'inactive' ),
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
		);
	}
}
