<?php
/**
 * Helpers functions.
 *
 * @package EaLab\WP_Deployer
 */

use EaLab\WP_Deployer\vendor\Dakwamine\Component\ComponentBasedObject;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\Config\ValueHandlerOption\ValueHandlerOptionConfigProviderManager;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\ItemValueHandlerBase;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Tracking\ItemValueHandler\ItemValueHandlerManager;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Api;
use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Settings;

function deploy_sync_content__encode_for_field_name( string $input ): string {
	// PHP converts the dot in the input name to underscore in the $_POST array,
	// so we need to convert the dot to something else.
	return str_replace( [ '.' ], [ '<dsc:dot>' ], $input );
}

/**
 * Build a message block for reactive-json structures.
 *
 * @param string      $message The message to set. Must be translated beforehand.
 * @param string|null $variant Optional. The variant, as one of the variants supported by React Bootstrap.
 *
 * @return array|null The structure with the message ready to be put in a content,
 *     or null if the block could not be built.
 */
function deploy_sync_content__form_structure__build_message_block( string $message, ?string $variant = null ): ?array {
	if ( empty( $message ) ) {
		return null;
	}

	$alert_message_block = array(
		'type'       => 'BsAlert',
		'attributes' => array(
			'dismissible' => true,
		),
		'content'    => array(
			'type'    => 'PreformattedMarkup',
			'content' => $message,
		),
	);

	if ( ! empty( $variant ) ) {
		// One of the BsAlert variants.
		$alert_message_block['attributes']['variant'] = $variant;
	}

	// This is needed to force the refresh of the alert component on frontend.
	// Without this, dismissed alerts will not be re-rendered if their content is the same.
	$unique_id = time();

	return array( $unique_id => $alert_message_block );
}

/**
 * Checks the importability status of the given post item.
 *
 * @param string $item_uuid Post item full UUID.
 * @param array  $exported_item The content of the item.
 *
 * @return array Result of the /wp-json/deploy-sync-content/v1/checkpost/{uuid} on the production instance.
 *     May return an empty array on errors such as the prod URL not set.
 *
 * @throws Throwable Unmanaged errors.
 */
function deploy_sync_content__check_data_changed_prod( string $item_uuid, array $exported_item ): array {
	$settings = Settings::getInstance();
	$url_prod = $settings->get( 'url_prod' );

	if ( empty( $url_prod ) || filter_var( $url_prod, FILTER_VALIDATE_URL ) === false ) {
		// There is no URL set for Prod, or it is not a valid URL.
		return array();
	}

	try {
		$data_changed = Api::callApiProd( 'POST', '/wp-json/deploy-sync-content/v1/checkpost/' . $item_uuid, $exported_item );

		return ! empty( json_decode( $data_changed, true ) ) ? json_decode( $data_changed, true ) : array();
	} catch ( Exception $e ) {
		// TODO: better error display.
		echo 'Caught exception: ', esc_html( $e->getMessage() ), "\n";

		return array();
	}
}

/**
 * Displays a success notice.
 *
 * @param string $message The message to display.
 *     Should be already translated, and unescaped; it will be escaped.
 */
function deploy_sync_content__success_notice( string $message ): void {
	echo '<div class="deploy-sync-content--notice notice-success is-dismissible">
        <p>' . wp_kses_post( $message ) . '</p>
    </div>';
}

/**
 * Displays an error notice.
 *
 * @param string $message The message to display.
 *     Should be already translated, and unescaped; it will be escaped.
 */
function deploy_sync_content__error_notice( string $message ): void {
	echo '<div class="deploy-sync-content--notice notice-error is-dismissible"> 
        <p>' . esc_html__( 'Error', 'deploy-sync-content' ) . ' : ' . wp_kses_post( $message ) . '</p>
    </div>';
}

/**
 * Displays a warning notice.
 *
 * @param string $message The message to display.
 *     Should be already translated, and unescaped; it will be escaped.
 */
function deploy_sync_content__warning_notice( string $message ): void {
	echo '<div class="deploy-sync-content--notice notice-warning is-dismissible"> 
        <p>' . wp_kses_post( $message ) . '</p>
    </div>';
}

/**
 * Displays an info notice.
 *
 * @param string $message The message to display.
 *     Should be already translated, and unescaped; it will be escaped.
 */
function deploy_sync_content__info_notice( string $message ): void {
	echo '<div class="deploy-sync-content--notice notice-info is-dismissible"> 
        <p>' . wp_kses_post( $message ) . '</p>
    </div>';
}

/**
 * Displays a notice.
 *
 * @param string $message The message to display.
 *     Should be already translated, and unescaped; it will be escaped.
 * @param string $type The type: warning, success, error, info.
 *     If unknown or unset, "info" will be used.
 */
function deploy_sync_content__notice( string $message, string $type = 'info' ): void {
	switch ( $type ) {
		case 'success':
			deploy_sync_content__success_notice( $message );
			break;
		case 'warning':
			deploy_sync_content__warning_notice( $message );
			break;
		case 'error':
			deploy_sync_content__error_notice( $message );
			break;
		default:
			deploy_sync_content__info_notice( $message );
	}
}

/**
 * Gets the item value handlers ID and name.
 *
 * @return array<string,string> Array keyed by ID, and having the translated label as value.
 */
function deploy_sync_content__get_item_value_handlers(): array {
	$item_value_handler_manager = ComponentBasedObject::getRootComponentByClassName( ItemValueHandlerManager::class, true );
	$handlers                   = $item_value_handler_manager->getHandlerClassNames();

	$handler_ids_and_names = array();

	foreach ( $handlers as $key => $val ) {
		if ( ! is_a( $val, ItemValueHandlerBase::class, true ) ) {
			continue;
		}

		$handler_ids_and_names[ $key ] = $val::getLabel();
	}

	return $handler_ids_and_names;
}

function deploy_sync_content__get_options_handler() {
	$options_handler = ComponentBasedObject::getRootComponentByClassName( ValueHandlerOptionConfigProviderManager::class, true )->getCurrentConfigProvider()->collect();

	return $options_handler;
}

function deploy_sync_content__capture_output( callable $callable ): string {
	ob_start();
	$callable();

	return ob_get_clean() || '';
}

/**
 * Reimplementation of move_uploaded_file.
 *
 * @param string $from The uploaded file to move.
 * @param string $to   Where to move the uploaded file.
 */
function deploy_sync_content__move_uploaded_file( string $from, string $to ): void {
	if ( ! is_uploaded_file( $from ) ) {
		return;
	}

	/** @var WP_Filesystem_Base $wp_filesystem */
	global $wp_filesystem;
	$wp_filesystem->move( $from, $to );
}