<?php
/**
 * REST Controller Trait
 *
 * Provides shared functionality for REST API controllers.
 *
 * @package Sequensy
 * @since 2.0.0
 */

declare(strict_types=1);

namespace Sequensy\Rest;

use Sequensy\Integrations\IntegrationStorage;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

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

/**
 * Trait RestControllerTrait
 *
 * Provides shared permission checks and helper methods for REST controllers.
 */
trait RestControllerTrait {

	/**
	 * Check permissions for REST API requests.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return bool|WP_Error True if allowed, WP_Error otherwise.
	 */
	public function permissions_check( // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
		WP_REST_Request $request
	): bool|WP_Error {
		if ( ! current_user_can( 'manage_options' ) ) {
			return $this->rest_error(
				'rest_forbidden',
				esc_html__( 'You do not have permission to access this resource.', 'sequensy' ),
				403
			);
		}

		return true;
	}

	/**
	 * Check if an integration is connected.
	 *
	 * @param string $integration Integration slug.
	 * @return bool True if connected or doesn't need connection.
	 */
	protected function is_integration_connected( string $integration ): bool {
		// WordPress core actions don't need connections.
		if ( ! $this->integration_requires_connection( $integration ) ) {
			return true;
		}

		return IntegrationStorage::is_connected( $integration );
	}

	/**
	 * Check if an integration requires a connection to function.
	 *
	 * Uses the package manifest to determine if auth is required,
	 * instead of a hardcoded slug list.
	 *
	 * @param string $integration Integration slug.
	 * @return bool True if connection is required.
	 */
	protected function integration_requires_connection( string $integration ): bool {
		$manifest = $this->get_package_loader()->get_manifest( $integration );

		return null !== $manifest && $manifest->requires_connection();
	}

	/**
	 * Get the package loader instance.
	 *
	 * @return \Sequensy\Packages\PackageLoader
	 */
	private function get_package_loader(): \Sequensy\Packages\PackageLoader {
		return \Sequensy\Container::getInstance()->get( 'package_loader' );
	}

	/**
	 * Create a standardized error response.
	 *
	 * @param string              $code    Error code.
	 * @param string              $message Human-readable message.
	 * @param int                 $status  HTTP status code.
	 * @param array<string,mixed> $data    Additional data.
	 * @return WP_Error
	 */
	protected function rest_error( string $code, string $message, int $status = 400, array $data = array() ): WP_Error {
		return new WP_Error( $code, $message, array_merge( array( 'status' => $status ), $data ) );
	}

	/**
	 * Create a standardized success response.
	 *
	 * @param mixed $data   Response data.
	 * @param int   $status HTTP status code.
	 * @return WP_REST_Response
	 */
	protected function rest_success( mixed $data, int $status = 200 ): WP_REST_Response {
		return new WP_REST_Response( $data, $status );
	}

	/**
	 * Create a validation error response with multiple field errors.
	 *
	 * @param array<string,string> $errors Field name => error message pairs.
	 * @return WP_Error
	 */
	protected function rest_validation_error( array $errors ): WP_Error {
		return new WP_Error(
			'validation_error',
			__( 'Validation failed.', 'sequensy' ),
			array(
				'status' => 422,
				'errors' => $errors,
			)
		);
	}
}
